xappy-0.5/0000755000175000017500000000000011005556727012341 5ustar richardrichardxappy-0.5/docs/0000755000175000017500000000000011005556727013271 5ustar richardrichardxappy-0.5/docs/api/0000755000175000017500000000000011005556727014042 5ustar richardrichardxappy-0.5/docs/api/api-objects.txt0000644000175000017500000007140311005555243017000 0ustar richardrichardxappy xappy-module.html xappy.set_replay_path xappy.replaylog-module.html#set_replay_path xappy._checkxapian xappy._checkxapian-module.html xappy._checkxapian.min_xapian_version xappy._checkxapian-module.html#min_xapian_version xappy._checkxapian.missing_features xappy._checkxapian-module.html#missing_features xappy._checkxapian.versions xappy._checkxapian-module.html#versions xappy.datastructures xappy.datastructures-module.html xappy.datastructures.log xappy.replaylog-module.html#log xappy.errors xappy.errors-module.html xappy.errors._rebase_xapian_exceptions xappy.errors-module.html#_rebase_xapian_exceptions xappy.fieldactions xappy.fieldactions-module.html xappy.fieldactions._act_index_exact xappy.fieldactions-module.html#_act_index_exact xappy.fieldactions._act_facet xappy.fieldactions-module.html#_act_facet xappy.fieldactions._act_sort_and_collapse xappy.fieldactions-module.html#_act_sort_and_collapse xappy.fieldactions.log xappy.replaylog-module.html#log xappy.fieldactions._act_store_content xappy.fieldactions-module.html#_act_store_content xappy.fieldactions._act_tag xappy.fieldactions-module.html#_act_tag xappy.fieldactions._act_index_freetext xappy.fieldactions-module.html#_act_index_freetext xappy.fieldmappings xappy.fieldmappings-module.html xappy.highlight xappy.highlight-module.html xappy.highlight.__test__ xappy.highlight-module.html#__test__ xappy.indexerconnection xappy.indexerconnection-module.html xappy.indexerconnection.log xappy.replaylog-module.html#log xappy.marshall xappy.marshall-module.html xappy.marshall.float_to_string xappy.marshall-module.html#float_to_string xappy.marshall.date_to_string xappy.marshall-module.html#date_to_string xappy.marshall._log xappy.replaylog-module.html#log xappy.memutils xappy.memutils-module.html xappy.memutils._get_physical_mem_sysconf xappy.memutils-module.html#_get_physical_mem_sysconf xappy.memutils.get_physical_memory xappy.memutils-module.html#get_physical_memory xappy.memutils._get_physical_mem_win32 xappy.memutils-module.html#_get_physical_mem_win32 xappy.parsedate xappy.parsedate-module.html xappy.parsedate.yyyymmdd_re xappy.parsedate-module.html#yyyymmdd_re xappy.parsedate.date_from_string xappy.parsedate-module.html#date_from_string xappy.parsedate.yyyy_mm_dd_re xappy.parsedate-module.html#yyyy_mm_dd_re xappy.replaylog xappy.replaylog-module.html xappy.replaylog.log xappy.replaylog-module.html#log xappy.replaylog._unproxy_call_and_args xappy.replaylog-module.html#_unproxy_call_and_args xappy.replaylog._replay_log xappy.replaylog-module.html#_replay_log xappy.replaylog.set_replay_path xappy.replaylog-module.html#set_replay_path xappy.replaylog._had_replay_log xappy.replaylog-module.html#_had_replay_log xappy.schema xappy.schema-module.html xappy.schema._log xappy.replaylog-module.html#log xappy.searchconnection xappy.searchconnection-module.html xappy.searchconnection._get_significant_digits xappy.searchconnection-module.html#_get_significant_digits xappy.searchconnection._log xappy.replaylog-module.html#log xappy.searchconnection.log xappy.replaylog-module.html#log xappy.datastructures.Field xappy.datastructures.Field-class.html xappy.datastructures.Field.name xappy.datastructures.Field-class.html#name xappy.datastructures.Field.value xappy.datastructures.Field-class.html#value xappy.datastructures.Field.__repr__ xappy.datastructures.Field-class.html#__repr__ xappy.datastructures.Field.__init__ xappy.datastructures.Field-class.html#__init__ xappy.datastructures.ProcessedDocument xappy.datastructures.ProcessedDocument-class.html xappy.datastructures.ProcessedDocument.add_term xappy.datastructures.ProcessedDocument-class.html#add_term xappy.datastructures.ProcessedDocument.id xappy.datastructures.ProcessedDocument-class.html#id xappy.datastructures.ProcessedDocument.__init__ xappy.datastructures.ProcessedDocument-class.html#__init__ xappy.datastructures.ProcessedDocument.prepare xappy.datastructures.ProcessedDocument-class.html#prepare xappy.datastructures.ProcessedDocument.get_value xappy.datastructures.ProcessedDocument-class.html#get_value xappy.datastructures.ProcessedDocument._get_data xappy.datastructures.ProcessedDocument-class.html#_get_data xappy.datastructures.ProcessedDocument._set_id xappy.datastructures.ProcessedDocument-class.html#_set_id xappy.datastructures.ProcessedDocument.add_value xappy.datastructures.ProcessedDocument-class.html#add_value xappy.datastructures.ProcessedDocument._fieldmappings xappy.datastructures.ProcessedDocument-class.html#_fieldmappings xappy.datastructures.ProcessedDocument._data xappy.datastructures.ProcessedDocument-class.html#_data xappy.datastructures.ProcessedDocument.data xappy.datastructures.ProcessedDocument-class.html#data xappy.datastructures.ProcessedDocument._set_data xappy.datastructures.ProcessedDocument-class.html#_set_data xappy.datastructures.ProcessedDocument._doc xappy.datastructures.ProcessedDocument-class.html#_doc xappy.datastructures.ProcessedDocument.__repr__ xappy.datastructures.ProcessedDocument-class.html#__repr__ xappy.datastructures.ProcessedDocument._get_id xappy.datastructures.ProcessedDocument-class.html#_get_id xappy.datastructures.UnprocessedDocument xappy.datastructures.UnprocessedDocument-class.html xappy.datastructures.UnprocessedDocument.fields xappy.datastructures.UnprocessedDocument-class.html#fields xappy.datastructures.UnprocessedDocument.__repr__ xappy.datastructures.UnprocessedDocument-class.html#__repr__ xappy.datastructures.UnprocessedDocument.id xappy.datastructures.UnprocessedDocument-class.html#id xappy.datastructures.UnprocessedDocument.__init__ xappy.datastructures.UnprocessedDocument-class.html#__init__ xappy.errors.IndexerError xappy.errors.IndexerError-class.html xappy.errors.SearchEngineError xappy.errors.SearchEngineError-class.html xappy.errors.SearchError xappy.errors.SearchError-class.html xappy.errors.XapianError xappy.errors.XapianError-class.html xappy.fieldactions.ActionContext xappy.fieldactions.ActionContext-class.html xappy.fieldactions.ActionContext.__init__ xappy.fieldactions.ActionContext-class.html#__init__ xappy.fieldactions.FieldActions xappy.fieldactions.FieldActions-class.html xappy.fieldactions.FieldActions._unsupported_actions xappy.fieldactions.FieldActions-class.html#_unsupported_actions xappy.fieldactions.FieldActions.__init__ xappy.fieldactions.FieldActions-class.html#__init__ xappy.fieldactions.FieldActions._action_info xappy.fieldactions.FieldActions-class.html#_action_info xappy.fieldactions.FieldActions.SORTABLE xappy.fieldactions.FieldActions-class.html#SORTABLE xappy.fieldactions.FieldActions.perform xappy.fieldactions.FieldActions-class.html#perform xappy.fieldactions.FieldActions.STORE_CONTENT xappy.fieldactions.FieldActions-class.html#STORE_CONTENT xappy.fieldactions.FieldActions.add xappy.fieldactions.FieldActions-class.html#add xappy.fieldactions.FieldActions.TAG xappy.fieldactions.FieldActions-class.html#TAG xappy.fieldactions.FieldActions.INDEX_EXACT xappy.fieldactions.FieldActions-class.html#INDEX_EXACT xappy.fieldactions.FieldActions.COLLAPSE xappy.fieldactions.FieldActions-class.html#COLLAPSE xappy.fieldactions.FieldActions.FACET xappy.fieldactions.FieldActions-class.html#FACET xappy.fieldactions.FieldActions.SORT_AND_COLLAPSE xappy.fieldactions.FieldActions-class.html#SORT_AND_COLLAPSE xappy.fieldactions.FieldActions.INDEX_FREETEXT xappy.fieldactions.FieldActions-class.html#INDEX_FREETEXT xappy.fieldactions.SortableMarshaller xappy.fieldactions.SortableMarshaller-class.html xappy.fieldactions.SortableMarshaller.marshall_string xappy.fieldactions.SortableMarshaller-class.html#marshall_string xappy.fieldactions.SortableMarshaller.marshall_date xappy.fieldactions.SortableMarshaller-class.html#marshall_date xappy.fieldactions.SortableMarshaller.marshall_float xappy.fieldactions.SortableMarshaller-class.html#marshall_float xappy.fieldactions.SortableMarshaller.get_marshall_function xappy.fieldactions.SortableMarshaller-class.html#get_marshall_function xappy.fieldactions.SortableMarshaller.__init__ xappy.fieldactions.SortableMarshaller-class.html#__init__ xappy.fieldmappings.FieldMappings xappy.fieldmappings.FieldMappings-class.html xappy.fieldmappings.FieldMappings.add_slot xappy.fieldmappings.FieldMappings-class.html#add_slot xappy.fieldmappings.FieldMappings._genPrefix xappy.fieldmappings.FieldMappings-class.html#_genPrefix xappy.fieldmappings.FieldMappings._prefixes xappy.fieldmappings.FieldMappings-class.html#_prefixes xappy.fieldmappings.FieldMappings.get_slot xappy.fieldmappings.FieldMappings-class.html#get_slot xappy.fieldmappings.FieldMappings.__init__ xappy.fieldmappings.FieldMappings-class.html#__init__ xappy.fieldmappings.FieldMappings.add_prefix xappy.fieldmappings.FieldMappings-class.html#add_prefix xappy.fieldmappings.FieldMappings._prefixcount xappy.fieldmappings.FieldMappings-class.html#_prefixcount xappy.fieldmappings.FieldMappings._slots xappy.fieldmappings.FieldMappings-class.html#_slots xappy.fieldmappings.FieldMappings.get_fieldname_from_prefix xappy.fieldmappings.FieldMappings-class.html#get_fieldname_from_prefix xappy.fieldmappings.FieldMappings.serialise xappy.fieldmappings.FieldMappings-class.html#serialise xappy.fieldmappings.FieldMappings.get_prefix xappy.fieldmappings.FieldMappings-class.html#get_prefix xappy.fieldmappings.FieldMappings._slotcount xappy.fieldmappings.FieldMappings-class.html#_slotcount xappy.highlight.Highlighter xappy.highlight.Highlighter-class.html xappy.highlight.Highlighter._split_re xappy.highlight.Highlighter-class.html#_split_re xappy.highlight.Highlighter._query_to_stemmed_words xappy.highlight.Highlighter-class.html#_query_to_stemmed_words xappy.highlight.Highlighter.makeSample xappy.highlight.Highlighter-class.html#makeSample xappy.highlight.Highlighter._strip_prefix xappy.highlight.Highlighter-class.html#_strip_prefix xappy.highlight.Highlighter._hl xappy.highlight.Highlighter-class.html#_hl xappy.highlight.Highlighter._split_text xappy.highlight.Highlighter-class.html#_split_text xappy.highlight.Highlighter.highlight xappy.highlight.Highlighter-class.html#highlight xappy.highlight.Highlighter.__init__ xappy.highlight.Highlighter-class.html#__init__ xappy.indexerconnection.FacetQueryTypeIter xappy.indexerconnection.FacetQueryTypeIter-class.html xappy.indexerconnection.FacetQueryTypeIter.next xappy.indexerconnection.FacetQueryTypeIter-class.html#next xappy.indexerconnection.FacetQueryTypeIter.__iter__ xappy.indexerconnection.FacetQueryTypeIter-class.html#__iter__ xappy.indexerconnection.FacetQueryTypeIter.__init__ xappy.indexerconnection.FacetQueryTypeIter-class.html#__init__ xappy.indexerconnection.IndexerConnection xappy.indexerconnection.IndexerConnection-class.html xappy.indexerconnection.IndexerConnection._load_config xappy.indexerconnection.IndexerConnection-class.html#_load_config xappy.indexerconnection.IndexerConnection._get_bytes_used_by_doc_terms xappy.indexerconnection.IndexerConnection-class.html#_get_bytes_used_by_doc_terms xappy.indexerconnection.IndexerConnection.remove_subfacet xappy.indexerconnection.IndexerConnection-class.html#remove_subfacet xappy.indexerconnection.IndexerConnection.process xappy.indexerconnection.IndexerConnection-class.html#process xappy.indexerconnection.IndexerConnection._assert_facet xappy.indexerconnection.IndexerConnection-class.html#_assert_facet xappy.indexerconnection.IndexerConnection.clear_field_actions xappy.indexerconnection.IndexerConnection-class.html#clear_field_actions xappy.indexerconnection.IndexerConnection.replace xappy.indexerconnection.IndexerConnection-class.html#replace xappy.indexerconnection.IndexerConnection.get_subfacets xappy.indexerconnection.IndexerConnection-class.html#get_subfacets xappy.indexerconnection.IndexerConnection.flush xappy.indexerconnection.IndexerConnection-class.html#flush xappy.indexerconnection.IndexerConnection.get_metadata xappy.indexerconnection.IndexerConnection-class.html#get_metadata xappy.indexerconnection.IndexerConnection.close xappy.indexerconnection.IndexerConnection-class.html#close xappy.indexerconnection.IndexerConnection.set_facet_for_query_type xappy.indexerconnection.IndexerConnection-class.html#set_facet_for_query_type xappy.indexerconnection.IndexerConnection.__init__ xappy.indexerconnection.IndexerConnection-class.html#__init__ xappy.indexerconnection.IndexerConnection.FacetQueryType_Never xappy.indexerconnection.IndexerConnection-class.html#FacetQueryType_Never xappy.indexerconnection.IndexerConnection.add_subfacet xappy.indexerconnection.IndexerConnection-class.html#add_subfacet xappy.indexerconnection.IndexerConnection.get_fields_with_actions xappy.indexerconnection.IndexerConnection-class.html#get_fields_with_actions xappy.indexerconnection.IndexerConnection.FacetQueryType_Preferred xappy.indexerconnection.IndexerConnection-class.html#FacetQueryType_Preferred xappy.indexerconnection.IndexerConnection.add xappy.indexerconnection.IndexerConnection-class.html#add xappy.indexerconnection.IndexerConnection.set_metadata xappy.indexerconnection.IndexerConnection-class.html#set_metadata xappy.indexerconnection.IndexerConnection.get_doccount xappy.indexerconnection.IndexerConnection-class.html#get_doccount xappy.indexerconnection.IndexerConnection.add_synonym xappy.indexerconnection.IndexerConnection-class.html#add_synonym xappy.indexerconnection.IndexerConnection._store_config xappy.indexerconnection.IndexerConnection-class.html#_store_config xappy.indexerconnection.IndexerConnection.remove_synonym xappy.indexerconnection.IndexerConnection-class.html#remove_synonym xappy.indexerconnection.IndexerConnection.iter_subfacets xappy.indexerconnection.IndexerConnection-class.html#iter_subfacets xappy.indexerconnection.IndexerConnection._make_synonym_key xappy.indexerconnection.IndexerConnection-class.html#_make_synonym_key xappy.indexerconnection.IndexerConnection.clear_synonyms xappy.indexerconnection.IndexerConnection-class.html#clear_synonyms xappy.indexerconnection.IndexerConnection.iter_synonyms xappy.indexerconnection.IndexerConnection-class.html#iter_synonyms xappy.indexerconnection.IndexerConnection.get_facets_for_query_type xappy.indexerconnection.IndexerConnection-class.html#get_facets_for_query_type xappy.indexerconnection.IndexerConnection.iterids xappy.indexerconnection.IndexerConnection-class.html#iterids xappy.indexerconnection.IndexerConnection._allocate_id xappy.indexerconnection.IndexerConnection-class.html#_allocate_id xappy.indexerconnection.IndexerConnection.add_field_action xappy.indexerconnection.IndexerConnection-class.html#add_field_action xappy.indexerconnection.IndexerConnection.set_max_mem_use xappy.indexerconnection.IndexerConnection-class.html#set_max_mem_use xappy.indexerconnection.IndexerConnection.get_document xappy.indexerconnection.IndexerConnection-class.html#get_document xappy.indexerconnection.IndexerConnection.iter_facet_query_types xappy.indexerconnection.IndexerConnection-class.html#iter_facet_query_types xappy.indexerconnection.IndexerConnection.delete xappy.indexerconnection.IndexerConnection-class.html#delete xappy.indexerconnection.PrefixedTermIter xappy.indexerconnection.PrefixedTermIter-class.html xappy.indexerconnection.PrefixedTermIter.next xappy.indexerconnection.PrefixedTermIter-class.html#next xappy.indexerconnection.PrefixedTermIter.__iter__ xappy.indexerconnection.PrefixedTermIter-class.html#__iter__ xappy.indexerconnection.PrefixedTermIter.__init__ xappy.indexerconnection.PrefixedTermIter-class.html#__init__ xappy.indexerconnection.SynonymIter xappy.indexerconnection.SynonymIter-class.html xappy.indexerconnection.SynonymIter.next xappy.indexerconnection.SynonymIter-class.html#next xappy.indexerconnection.SynonymIter.__iter__ xappy.indexerconnection.SynonymIter-class.html#__iter__ xappy.indexerconnection.SynonymIter.__init__ xappy.indexerconnection.SynonymIter-class.html#__init__ xappy.replaylog.LoggedProxy xappy.replaylog.LoggedProxy-class.html xappy.replaylog.LoggedProxy.__str__ xappy.replaylog.LoggedProxy-class.html#__str__ xappy.replaylog.LoggedProxy.__getattribute__ xappy.replaylog.LoggedProxy-class.html#__getattribute__ xappy.replaylog.LoggedProxy.__iter__ xappy.replaylog.LoggedProxy-class.html#__iter__ xappy.replaylog.LoggedProxy.__len__ xappy.replaylog.LoggedProxy-class.html#__len__ xappy.replaylog.LoggedProxy.__init__ xappy.replaylog.LoggedProxy-class.html#__init__ xappy.replaylog.LoggedProxy.__repr__ xappy.replaylog.LoggedProxy-class.html#__repr__ xappy.replaylog.LoggedProxyMethod xappy.replaylog.LoggedProxyMethod-class.html xappy.replaylog.LoggedProxyMethod.__call__ xappy.replaylog.LoggedProxyMethod-class.html#__call__ xappy.replaylog.LoggedProxyMethod.__init__ xappy.replaylog.LoggedProxyMethod-class.html#__init__ xappy.replaylog.NotifyingDeleteObject xappy.replaylog.NotifyingDeleteObject-class.html xappy.replaylog.NotifyingDeleteObject.__del__ xappy.replaylog.NotifyingDeleteObject-class.html#__del__ xappy.replaylog.NotifyingDeleteObject.__init__ xappy.replaylog.NotifyingDeleteObject-class.html#__init__ xappy.replaylog.ReplayLog xappy.replaylog.ReplayLog-class.html xappy.replaylog.ReplayLog.log_call xappy.replaylog.ReplayLog-class.html#log_call xappy.replaylog.ReplayLog._get_xap_name xappy.replaylog.ReplayLog-class.html#_get_xap_name xappy.replaylog.ReplayLog._repr_args xappy.replaylog.ReplayLog-class.html#_repr_args xappy.replaylog.ReplayLog._get_obj_num xappy.replaylog.ReplayLog-class.html#_get_obj_num xappy.replaylog.ReplayLog.__init__ xappy.replaylog.ReplayLog-class.html#__init__ xappy.replaylog.ReplayLog._repr_arg xappy.replaylog.ReplayLog-class.html#_repr_arg xappy.replaylog.ReplayLog.log_retval xappy.replaylog.ReplayLog-class.html#log_retval xappy.replaylog.ReplayLog._get_call_id xappy.replaylog.ReplayLog-class.html#_get_call_id xappy.replaylog.ReplayLog._is_xap_obj xappy.replaylog.ReplayLog-class.html#_is_xap_obj xappy.replaylog.ReplayLog._log xappy.replaylog.ReplayLog-class.html#_log xappy.replaylog.ReplayLog.log_except xappy.replaylog.ReplayLog-class.html#log_except xappy.replaylog.ReplayLog._obj_gone xappy.replaylog.ReplayLog-class.html#_obj_gone xappy.schema.Schema xappy.schema.Schema-class.html xappy.schema.Schema.__init__ xappy.schema.Schema-class.html#__init__ xappy.searchconnection.SearchConnection xappy.searchconnection.SearchConnection-class.html xappy.searchconnection.SearchConnection._load_config xappy.searchconnection.SearchConnection-class.html#_load_config xappy.searchconnection.SearchConnection._facet_query_never xappy.searchconnection.SearchConnection-class.html#_facet_query_never xappy.searchconnection.SearchConnection.query_none xappy.searchconnection.SearchConnection-class.html#query_none xappy.searchconnection.SearchConnection.query_multweight xappy.searchconnection.SearchConnection-class.html#query_multweight xappy.searchconnection.SearchConnection._qp_flags_phrase xappy.searchconnection.SearchConnection-class.html#_qp_flags_phrase xappy.searchconnection.SearchConnection.reopen xappy.searchconnection.SearchConnection-class.html#reopen xappy.searchconnection.SearchConnection.query_parse xappy.searchconnection.SearchConnection-class.html#query_parse xappy.searchconnection.SearchConnection.get_metadata xappy.searchconnection.SearchConnection-class.html#get_metadata xappy.searchconnection.SearchConnection.close xappy.searchconnection.SearchConnection-class.html#close xappy.searchconnection.SearchConnection._query_parse_with_prefix xappy.searchconnection.SearchConnection-class.html#_query_parse_with_prefix xappy.searchconnection.SearchConnection.__init__ xappy.searchconnection.SearchConnection-class.html#__init__ xappy.searchconnection.SearchConnection._query_parse_with_fallback xappy.searchconnection.SearchConnection-class.html#_query_parse_with_fallback xappy.searchconnection.SearchConnection.query_all xappy.searchconnection.SearchConnection-class.html#query_all xappy.searchconnection.SearchConnection.query_similar xappy.searchconnection.SearchConnection-class.html#query_similar xappy.searchconnection.SearchConnection.query_adjust xappy.searchconnection.SearchConnection-class.html#query_adjust xappy.searchconnection.SearchConnection.OP_AND xappy.searchconnection.SearchConnection-class.html#OP_AND xappy.searchconnection.SearchConnection.query_field xappy.searchconnection.SearchConnection-class.html#query_field xappy.searchconnection.SearchConnection.get_doccount xappy.searchconnection.SearchConnection-class.html#get_doccount xappy.searchconnection.SearchConnection._get_sort_type xappy.searchconnection.SearchConnection-class.html#_get_sort_type xappy.searchconnection.SearchConnection._qp_flags_bool xappy.searchconnection.SearchConnection-class.html#_qp_flags_bool xappy.searchconnection.SearchConnection._prepare_queryparser xappy.searchconnection.SearchConnection-class.html#_prepare_queryparser xappy.searchconnection.SearchConnection.spell_correct xappy.searchconnection.SearchConnection-class.html#spell_correct xappy.searchconnection.SearchConnection.__del__ xappy.searchconnection.SearchConnection-class.html#__del__ xappy.searchconnection.SearchConnection.query_facet xappy.searchconnection.SearchConnection-class.html#query_facet xappy.searchconnection.SearchConnection._qp_flags_base xappy.searchconnection.SearchConnection-class.html#_qp_flags_base xappy.searchconnection.SearchConnection.query_filter xappy.searchconnection.SearchConnection-class.html#query_filter xappy.searchconnection.SearchConnection.iter_synonyms xappy.searchconnection.SearchConnection-class.html#iter_synonyms xappy.searchconnection.SearchConnection._get_prefix_from_term xappy.searchconnection.SearchConnection-class.html#_get_prefix_from_term xappy.searchconnection.SearchConnection.iterids xappy.searchconnection.SearchConnection-class.html#iterids xappy.searchconnection.SearchConnection.can_sort_on xappy.searchconnection.SearchConnection-class.html#can_sort_on xappy.searchconnection.SearchConnection._perform_expand xappy.searchconnection.SearchConnection-class.html#_perform_expand xappy.searchconnection.SearchConnection.append_close_handler xappy.searchconnection.SearchConnection-class.html#append_close_handler xappy.searchconnection.SearchConnection.search xappy.searchconnection.SearchConnection-class.html#search xappy.searchconnection.SearchConnection.query_range xappy.searchconnection.SearchConnection-class.html#query_range xappy.searchconnection.SearchConnection.get_document xappy.searchconnection.SearchConnection-class.html#get_document xappy.searchconnection.SearchConnection._index xappy.searchconnection.SearchConnection-class.html#_index xappy.searchconnection.SearchConnection._get_eterms xappy.searchconnection.SearchConnection-class.html#_get_eterms xappy.searchconnection.SearchConnection.query_composite xappy.searchconnection.SearchConnection-class.html#query_composite xappy.searchconnection.SearchConnection.OP_OR xappy.searchconnection.SearchConnection-class.html#OP_OR xappy.searchconnection.SearchConnection.can_collapse_on xappy.searchconnection.SearchConnection-class.html#can_collapse_on xappy.searchconnection.SearchConnection._qp_flags_synonym xappy.searchconnection.SearchConnection-class.html#_qp_flags_synonym xappy.searchconnection.SearchConnection.significant_terms xappy.searchconnection.SearchConnection-class.html#significant_terms xappy.searchconnection.SearchConnection.ExpandDecider xappy.searchconnection.SearchConnection.ExpandDecider-class.html xappy.searchconnection.SearchConnection.ExpandDecider xappy.searchconnection.SearchConnection.ExpandDecider-class.html xappy.searchconnection.SearchConnection.ExpandDecider.__call__ xappy.searchconnection.SearchConnection.ExpandDecider-class.html#__call__ xappy.searchconnection.SearchConnection.ExpandDecider.__init__ xappy.searchconnection.SearchConnection.ExpandDecider-class.html#__init__ xappy.searchconnection.SearchResult xappy.searchconnection.SearchResult-class.html xappy.datastructures.ProcessedDocument.add_term xappy.datastructures.ProcessedDocument-class.html#add_term xappy.datastructures.ProcessedDocument.id xappy.datastructures.ProcessedDocument-class.html#id xappy.searchconnection.SearchResult.__init__ xappy.searchconnection.SearchResult-class.html#__init__ xappy.datastructures.ProcessedDocument.prepare xappy.datastructures.ProcessedDocument-class.html#prepare xappy.datastructures.ProcessedDocument.get_value xappy.datastructures.ProcessedDocument-class.html#get_value xappy.datastructures.ProcessedDocument._get_data xappy.datastructures.ProcessedDocument-class.html#_get_data xappy.datastructures.ProcessedDocument._set_id xappy.datastructures.ProcessedDocument-class.html#_set_id xappy.searchconnection.SearchResult._get_language xappy.searchconnection.SearchResult-class.html#_get_language xappy.datastructures.ProcessedDocument.add_value xappy.datastructures.ProcessedDocument-class.html#add_value xappy.datastructures.ProcessedDocument._fieldmappings xappy.datastructures.ProcessedDocument-class.html#_fieldmappings xappy.datastructures.ProcessedDocument._data xappy.datastructures.ProcessedDocument-class.html#_data xappy.datastructures.ProcessedDocument.data xappy.datastructures.ProcessedDocument-class.html#data xappy.datastructures.ProcessedDocument._set_data xappy.datastructures.ProcessedDocument-class.html#_set_data xappy.datastructures.ProcessedDocument._doc xappy.datastructures.ProcessedDocument-class.html#_doc xappy.searchconnection.SearchResult.__repr__ xappy.searchconnection.SearchResult-class.html#__repr__ xappy.datastructures.ProcessedDocument._get_id xappy.datastructures.ProcessedDocument-class.html#_get_id xappy.searchconnection.SearchResult.highlight xappy.searchconnection.SearchResult-class.html#highlight xappy.searchconnection.SearchResult.summarise xappy.searchconnection.SearchResult-class.html#summarise xappy.searchconnection.SearchResultIter xappy.searchconnection.SearchResultIter-class.html xappy.searchconnection.SearchResultIter.next xappy.searchconnection.SearchResultIter-class.html#next xappy.searchconnection.SearchResultIter.__init__ xappy.searchconnection.SearchResultIter-class.html#__init__ xappy.searchconnection.SearchResults xappy.searchconnection.SearchResults-class.html xappy.searchconnection.SearchResults._reorder_by_similarity xappy.searchconnection.SearchResults-class.html#_reorder_by_similarity xappy.searchconnection.SearchResults._get_startrank xappy.searchconnection.SearchResults-class.html#_get_startrank xappy.searchconnection.SearchResults._get_upper_bound xappy.searchconnection.SearchResults-class.html#_get_upper_bound xappy.searchconnection.SearchResults._estimate_is_exact xappy.searchconnection.SearchResults-class.html#_estimate_is_exact xappy.searchconnection.SearchResults._get_human_readable_estimate xappy.searchconnection.SearchResults-class.html#_get_human_readable_estimate xappy.searchconnection.SearchResults.estimate_is_exact xappy.searchconnection.SearchResults-class.html#estimate_is_exact xappy.searchconnection.SearchResults._cluster xappy.searchconnection.SearchResults-class.html#_cluster xappy.searchconnection.SearchResults.matches_estimated xappy.searchconnection.SearchResults-class.html#matches_estimated xappy.searchconnection.SearchResults.__init__ xappy.searchconnection.SearchResults-class.html#__init__ xappy.searchconnection.SearchResults.__getitem__ xappy.searchconnection.SearchResults-class.html#__getitem__ xappy.searchconnection.SearchResults.get_suggested_facets xappy.searchconnection.SearchResults-class.html#get_suggested_facets xappy.searchconnection.SearchResults.startrank xappy.searchconnection.SearchResults-class.html#startrank xappy.searchconnection.SearchResults.more_matches xappy.searchconnection.SearchResults-class.html#more_matches xappy.searchconnection.SearchResults.get_top_tags xappy.searchconnection.SearchResults-class.html#get_top_tags xappy.searchconnection.SearchResults.get_hit xappy.searchconnection.SearchResults-class.html#get_hit xappy.searchconnection.SearchResults.__len__ xappy.searchconnection.SearchResults-class.html#__len__ xappy.searchconnection.SearchResults.matches_human_readable_estimate xappy.searchconnection.SearchResults-class.html#matches_human_readable_estimate xappy.searchconnection.SearchResults.matches_lower_bound xappy.searchconnection.SearchResults-class.html#matches_lower_bound xappy.searchconnection.SearchResults._get_more_matches xappy.searchconnection.SearchResults-class.html#_get_more_matches xappy.searchconnection.SearchResults._reorder_by_clusters xappy.searchconnection.SearchResults-class.html#_reorder_by_clusters xappy.searchconnection.SearchResults._make_expand_decider xappy.searchconnection.SearchResults-class.html#_make_expand_decider xappy.searchconnection.SearchResults._get_endrank xappy.searchconnection.SearchResults-class.html#_get_endrank xappy.searchconnection.SearchResults.__iter__ xappy.searchconnection.SearchResults-class.html#__iter__ xappy.searchconnection.SearchResults._get_estimated xappy.searchconnection.SearchResults-class.html#_get_estimated xappy.searchconnection.SearchResults._get_lower_bound xappy.searchconnection.SearchResults-class.html#_get_lower_bound xappy.searchconnection.SearchResults.__repr__ xappy.searchconnection.SearchResults-class.html#__repr__ xappy.searchconnection.SearchResults.endrank xappy.searchconnection.SearchResults-class.html#endrank xappy.searchconnection.SearchResults.matches_upper_bound xappy.searchconnection.SearchResults-class.html#matches_upper_bound xappy-0.5/docs/api/class-tree.html0000644000175000017500000002350411005555242016765 0ustar richardrichard Class Hierarchy
 
[frames] | no frames]
[ Module Hierarchy | Class Hierarchy ]

Class Hierarchy

xappy-0.5/docs/api/crarr.png0000644000175000017500000000052411005555242015651 0ustar richardrichardPNG  IHDR eE,tEXtCreation TimeTue 22 Aug 2006 00:43:10 -0500` XtIME)} pHYsnu>gAMA aEPLTEðf4sW ЊrD`@bCܖX{`,lNo@xdE螊dƴ~TwvtRNS@fMIDATxc`@0&+(;; /EXؑ? n  b;'+Y#(r<"IENDB`xappy-0.5/docs/api/epydoc.css0000644000175000017500000003643011005555242016034 0ustar richardrichard /* Epydoc CSS Stylesheet * * This stylesheet can be used to customize the appearance of epydoc's * HTML output. * */ /* Default Colors & Styles * - Set the default foreground & background color with 'body'; and * link colors with 'a:link' and 'a:visited'. * - Use bold for decision list terms. * - The heading styles defined here are used for headings *within* * docstring descriptions. All headings used by epydoc itself use * either class='epydoc' or class='toc' (CSS styles for both * defined below). */ body { background: #ffffff; color: #000000; } a:link { color: #0000ff; } a:visited { color: #204080; } dt { font-weight: bold; } h1 { font-size: +140%; font-style: italic; font-weight: bold; } h2 { font-size: +125%; font-style: italic; font-weight: bold; } h3 { font-size: +110%; font-style: italic; font-weight: normal; } code { font-size: 100%; } /* Page Header & Footer * - The standard page header consists of a navigation bar (with * pointers to standard pages such as 'home' and 'trees'); a * breadcrumbs list, which can be used to navigate to containing * classes or modules; options links, to show/hide private * variables and to show/hide frames; and a page title (using *

). The page title may be followed by a link to the * corresponding source code (using 'span.codelink'). * - The footer consists of a navigation bar, a timestamp, and a * pointer to epydoc's homepage. */ h1.epydoc { margin: 0; font-size: +140%; font-weight: bold; } h2.epydoc { font-size: +130%; font-weight: bold; } h3.epydoc { font-size: +115%; font-weight: bold; } td h3.epydoc { font-size: +115%; font-weight: bold; margin-bottom: 0; } table.navbar { background: #a0c0ff; color: #000000; border: 2px groove #c0d0d0; } table.navbar table { color: #000000; } th.navbar-select { background: #70b0ff; color: #000000; } table.navbar a { text-decoration: none; } table.navbar a:link { color: #0000ff; } table.navbar a:visited { color: #204080; } span.breadcrumbs { font-size: 85%; font-weight: bold; } span.options { font-size: 70%; } span.codelink { font-size: 85%; } td.footer { font-size: 85%; } /* Table Headers * - Each summary table and details section begins with a 'header' * row. This row contains a section title (marked by * 'span.table-header') as well as a show/hide private link * (marked by 'span.options', defined above). * - Summary tables that contain user-defined groups mark those * groups using 'group header' rows. */ td.table-header { background: #70b0ff; color: #000000; border: 1px solid #608090; } td.table-header table { color: #000000; } td.table-header table a:link { color: #0000ff; } td.table-header table a:visited { color: #204080; } span.table-header { font-size: 120%; font-weight: bold; } th.group-header { background: #c0e0f8; color: #000000; text-align: left; font-style: italic; font-size: 115%; border: 1px solid #608090; } /* Summary Tables (functions, variables, etc) * - Each object is described by a single row of the table with * two cells. The left cell gives the object's type, and is * marked with 'code.summary-type'. The right cell gives the * object's name and a summary description. * - CSS styles for the table's header and group headers are * defined above, under 'Table Headers' */ table.summary { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin-bottom: 0.5em; } td.summary { border: 1px solid #608090; } code.summary-type { font-size: 85%; } table.summary a:link { color: #0000ff; } table.summary a:visited { color: #204080; } /* Details Tables (functions, variables, etc) * - Each object is described in its own div. * - A single-row summary table w/ table-header is used as * a header for each details section (CSS style for table-header * is defined above, under 'Table Headers'). */ table.details { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin: .2em 0 0 0; } table.details table { color: #000000; } table.details a:link { color: #0000ff; } table.details a:visited { color: #204080; } /* Fields */ dl.fields { margin-left: 2em; margin-top: 1em; margin-bottom: 1em; } dl.fields dd ul { margin-left: 0em; padding-left: 0em; } div.fields { margin-left: 2em; } div.fields p { margin-bottom: 0.5em; } /* Index tables (identifier index, term index, etc) * - link-index is used for indices containing lists of links * (namely, the identifier index & term index). * - index-where is used in link indices for the text indicating * the container/source for each link. * - metadata-index is used for indices containing metadata * extracted from fields (namely, the bug index & todo index). */ table.link-index { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; } td.link-index { border-width: 0px; } table.link-index a:link { color: #0000ff; } table.link-index a:visited { color: #204080; } span.index-where { font-size: 70%; } table.metadata-index { border-collapse: collapse; background: #e8f0f8; color: #000000; border: 1px solid #608090; margin: .2em 0 0 0; } td.metadata-index { border-width: 1px; border-style: solid; } table.metadata-index a:link { color: #0000ff; } table.metadata-index a:visited { color: #204080; } /* Function signatures * - sig* is used for the signature in the details section. * - .summary-sig* is used for the signature in the summary * table, and when listing property accessor functions. * */ .sig-name { color: #006080; } .sig-arg { color: #008060; } .sig-default { color: #602000; } .summary-sig { font-family: monospace; } .summary-sig-name { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:link { color: #006080; font-weight: bold; } table.summary a.summary-sig-name:visited { color: #006080; font-weight: bold; } .summary-sig-arg { color: #006040; } .summary-sig-default { color: #501800; } /* To render variables, classes etc. like functions */ table.summary .summary-name { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:link { color: #006080; font-weight: bold; font-family: monospace; } table.summary a.summary-name:visited { color: #006080; font-weight: bold; font-family: monospace; } /* Variable values * - In the 'variable details' sections, each varaible's value is * listed in a 'pre.variable' box. The width of this box is * restricted to 80 chars; if the value's repr is longer than * this it will be wrapped, using a backslash marked with * class 'variable-linewrap'. If the value's repr is longer * than 3 lines, the rest will be ellided; and an ellipsis * marker ('...' marked with 'variable-ellipsis') will be used. * - If the value is a string, its quote marks will be marked * with 'variable-quote'. * - If the variable is a regexp, it is syntax-highlighted using * the re* CSS classes. */ pre.variable { padding: .5em; margin: 0; background: #dce4ec; color: #000000; border: 1px solid #708890; } .variable-linewrap { color: #604000; font-weight: bold; } .variable-ellipsis { color: #604000; font-weight: bold; } .variable-quote { color: #604000; font-weight: bold; } .variable-group { color: #008000; font-weight: bold; } .variable-op { color: #604000; font-weight: bold; } .variable-string { color: #006030; } .variable-unknown { color: #a00000; font-weight: bold; } .re { color: #000000; } .re-char { color: #006030; } .re-op { color: #600000; } .re-group { color: #003060; } .re-ref { color: #404040; } /* Base tree * - Used by class pages to display the base class hierarchy. */ pre.base-tree { font-size: 80%; margin: 0; } /* Frames-based table of contents headers * - Consists of two frames: one for selecting modules; and * the other listing the contents of the selected module. * - h1.toc is used for each frame's heading * - h2.toc is used for subheadings within each frame. */ h1.toc { text-align: center; font-size: 105%; margin: 0; font-weight: bold; padding: 0; } h2.toc { font-size: 100%; font-weight: bold; margin: 0.5em 0 0 -0.3em; } /* Syntax Highlighting for Source Code * - doctest examples are displayed in a 'pre.py-doctest' block. * If the example is in a details table entry, then it will use * the colors specified by the 'table pre.py-doctest' line. * - Source code listings are displayed in a 'pre.py-src' block. * Each line is marked with 'span.py-line' (used to draw a line * down the left margin, separating the code from the line * numbers). Line numbers are displayed with 'span.py-lineno'. * The expand/collapse block toggle button is displayed with * 'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not * modify the font size of the text.) * - If a source code page is opened with an anchor, then the * corresponding code block will be highlighted. The code * block's header is highlighted with 'py-highlight-hdr'; and * the code block's body is highlighted with 'py-highlight'. * - The remaining py-* classes are used to perform syntax * highlighting (py-string for string literals, py-name for names, * etc.) */ pre.py-doctest { padding: .5em; margin: 1em; background: #e8f0f8; color: #000000; border: 1px solid #708890; } table pre.py-doctest { background: #dce4ec; color: #000000; } pre.py-src { border: 2px solid #000000; background: #f0f0f0; color: #000000; } .py-line { border-left: 2px solid #000000; margin-left: .2em; padding-left: .4em; } .py-lineno { font-style: italic; font-size: 90%; padding-left: .5em; } a.py-toggle { text-decoration: none; } div.py-highlight-hdr { border-top: 2px solid #000000; border-bottom: 2px solid #000000; background: #d8e8e8; } div.py-highlight { border-bottom: 2px solid #000000; background: #d0e0e0; } .py-prompt { color: #005050; font-weight: bold;} .py-more { color: #005050; font-weight: bold;} .py-string { color: #006030; } .py-comment { color: #003060; } .py-keyword { color: #600000; } .py-output { color: #404040; } .py-name { color: #000050; } .py-name:link { color: #000050 !important; } .py-name:visited { color: #000050 !important; } .py-number { color: #005000; } .py-defname { color: #000060; font-weight: bold; } .py-def-name { color: #000060; font-weight: bold; } .py-base-class { color: #000060; } .py-param { color: #000060; } .py-docstring { color: #006030; } .py-decorator { color: #804020; } /* Use this if you don't want links to names underlined: */ /*a.py-name { text-decoration: none; }*/ /* Graphs & Diagrams * - These CSS styles are used for graphs & diagrams generated using * Graphviz dot. 'img.graph-without-title' is used for bare * diagrams (to remove the border created by making the image * clickable). */ img.graph-without-title { border: none; } img.graph-with-title { border: 1px solid #000000; } span.graph-title { font-weight: bold; } span.graph-caption { } /* General-purpose classes * - 'p.indent-wrapped-lines' defines a paragraph whose first line * is not indented, but whose subsequent lines are. * - The 'nomargin-top' class is used to remove the top margin (e.g. * from lists). The 'nomargin' class is used to remove both the * top and bottom margin (but not the left or right margin -- * for lists, that would cause the bullets to disappear.) */ p.indent-wrapped-lines { padding: 0 0 0 7em; text-indent: -7em; margin: 0; } .nomargin-top { margin-top: 0; } .nomargin { margin-top: 0; margin-bottom: 0; } /* HTML Log */ div.log-block { padding: 0; margin: .5em 0 .5em 0; background: #e8f0f8; color: #000000; border: 1px solid #000000; } div.log-error { padding: .1em .3em .1em .3em; margin: 4px; background: #ffb0b0; color: #000000; border: 1px solid #000000; } div.log-warning { padding: .1em .3em .1em .3em; margin: 4px; background: #ffffb0; color: #000000; border: 1px solid #000000; } div.log-info { padding: .1em .3em .1em .3em; margin: 4px; background: #b0ffb0; color: #000000; border: 1px solid #000000; } h2.log-hdr { background: #70b0ff; color: #000000; margin: 0; padding: 0em 0.5em 0em 0.5em; border-bottom: 1px solid #000000; font-size: 110%; } p.log { font-weight: bold; margin: .5em 0 .5em 0; } tr.opt-changed { color: #000000; font-weight: bold; } tr.opt-default { color: #606060; } pre.log { margin: 0; padding: 0; padding-left: 1em; } xappy-0.5/docs/api/epydoc.js0000644000175000017500000002360211005555242015655 0ustar richardrichardfunction toggle_private() { // Search for any private/public links on this page. Store // their old text in "cmd," so we will know what action to // take; and change their text to the opposite action. var cmd = "?"; var elts = document.getElementsByTagName("a"); for(var i=0; i...
"; elt.innerHTML = s; } } function toggle(id) { elt = document.getElementById(id+"-toggle"); if (elt.innerHTML == "-") collapse(id); else expand(id); return false; } function highlight(id) { var elt = document.getElementById(id+"-def"); if (elt) elt.className = "py-highlight-hdr"; var elt = document.getElementById(id+"-expanded"); if (elt) elt.className = "py-highlight"; var elt = document.getElementById(id+"-collapsed"); if (elt) elt.className = "py-highlight"; } function num_lines(s) { var n = 1; var pos = s.indexOf("\n"); while ( pos > 0) { n += 1; pos = s.indexOf("\n", pos+1); } return n; } // Collapse all blocks that mave more than `min_lines` lines. function collapse_all(min_lines) { var elts = document.getElementsByTagName("div"); for (var i=0; i 0) if (elt.id.substring(split, elt.id.length) == "-expanded") if (num_lines(elt.innerHTML) > min_lines) collapse(elt.id.substring(0, split)); } } function expandto(href) { var start = href.indexOf("#")+1; if (start != 0 && start != href.length) { if (href.substring(start, href.length) != "-") { collapse_all(4); pos = href.indexOf(".", start); while (pos != -1) { var id = href.substring(start, pos); expand(id); pos = href.indexOf(".", pos+1); } var id = href.substring(start, href.length); expand(id); highlight(id); } } } function kill_doclink(id) { var parent = document.getElementById(id); parent.removeChild(parent.childNodes.item(0)); } function auto_kill_doclink(ev) { if (!ev) var ev = window.event; if (!this.contains(ev.toElement)) { var parent = document.getElementById(this.parentID); parent.removeChild(parent.childNodes.item(0)); } } function doclink(id, name, targets_id) { var elt = document.getElementById(id); // If we already opened the box, then destroy it. // (This case should never occur, but leave it in just in case.) if (elt.childNodes.length > 1) { elt.removeChild(elt.childNodes.item(0)); } else { // The outer box: relative + inline positioning. var box1 = document.createElement("div"); box1.style.position = "relative"; box1.style.display = "inline"; box1.style.top = 0; box1.style.left = 0; // A shadow for fun var shadow = document.createElement("div"); shadow.style.position = "absolute"; shadow.style.left = "-1.3em"; shadow.style.top = "-1.3em"; shadow.style.background = "#404040"; // The inner box: absolute positioning. var box2 = document.createElement("div"); box2.style.position = "relative"; box2.style.border = "1px solid #a0a0a0"; box2.style.left = "-.2em"; box2.style.top = "-.2em"; box2.style.background = "white"; box2.style.padding = ".3em .4em .3em .4em"; box2.style.fontStyle = "normal"; box2.onmouseout=auto_kill_doclink; box2.parentID = id; // Get the targets var targets_elt = document.getElementById(targets_id); var targets = targets_elt.getAttribute("targets"); var links = ""; target_list = targets.split(","); for (var i=0; i" + target[0] + ""; } // Put it all together. elt.insertBefore(box1, elt.childNodes.item(0)); //box1.appendChild(box2); box1.appendChild(shadow); shadow.appendChild(box2); box2.innerHTML = "Which "+name+" do you want to see documentation for?" + ""; } return false; } function get_anchor() { var href = location.href; var start = href.indexOf("#")+1; if ((start != 0) && (start != href.length)) return href.substring(start, href.length); } function redirect_url(dottedName) { // Scan through each element of the "pages" list, and check // if "name" matches with any of them. for (var i=0; i-m" or "-c"; // extract the portion & compare it to dottedName. var pagename = pages[i].substring(0, pages[i].length-2); if (pagename == dottedName.substring(0,pagename.length)) { // We've found a page that matches `dottedName`; // construct its URL, using leftover `dottedName` // content to form an anchor. var pagetype = pages[i].charAt(pages[i].length-1); var url = pagename + ((pagetype=="m")?"-module.html": "-class.html"); if (dottedName.length > pagename.length) url += "#" + dottedName.substring(pagename.length+1, dottedName.length); return url; } } } xappy-0.5/docs/api/frames.html0000644000175000017500000000107711005555242016201 0ustar richardrichard xappy xappy-0.5/docs/api/help.html0000644000175000017500000002522211005555242015652 0ustar richardrichard Help
 
[frames] | no frames]

API Documentation

This document contains the API (Application Programming Interface) documentation for xappy. Documentation for the Python objects defined by the project is divided into separate pages for each package, module, and class. The API documentation also includes two pages containing information about the project as a whole: a trees page, and an index page.

Object Documentation

Each Package Documentation page contains:

  • A description of the package.
  • A list of the modules and sub-packages contained by the package.
  • A summary of the classes defined by the package.
  • A summary of the functions defined by the package.
  • A summary of the variables defined by the package.
  • A detailed description of each function defined by the package.
  • A detailed description of each variable defined by the package.

Each Module Documentation page contains:

  • A description of the module.
  • A summary of the classes defined by the module.
  • A summary of the functions defined by the module.
  • A summary of the variables defined by the module.
  • A detailed description of each function defined by the module.
  • A detailed description of each variable defined by the module.

Each Class Documentation page contains:

  • A class inheritance diagram.
  • A list of known subclasses.
  • A description of the class.
  • A summary of the methods defined by the class.
  • A summary of the instance variables defined by the class.
  • A summary of the class (static) variables defined by the class.
  • A detailed description of each method defined by the class.
  • A detailed description of each instance variable defined by the class.
  • A detailed description of each class (static) variable defined by the class.

Project Documentation

The Trees page contains the module and class hierarchies:

  • The module hierarchy lists every package and module, with modules grouped into packages. At the top level, and within each package, modules and sub-packages are listed alphabetically.
  • The class hierarchy lists every class, grouped by base class. If a class has more than one base class, then it will be listed under each base class. At the top level, and under each base class, classes are listed alphabetically.

The Index page contains indices of terms and identifiers:

  • The term index lists every term indexed by any object's documentation. For each term, the index provides links to each place where the term is indexed.
  • The identifier index lists the (short) name of every package, module, class, method, function, variable, and parameter. For each identifier, the index provides a short description, and a link to its documentation.

The Table of Contents

The table of contents occupies the two frames on the left side of the window. The upper-left frame displays the project contents, and the lower-left frame displays the module contents:

Project
Contents
...
API
Documentation
Frame


Module
Contents
 
...
 

The project contents frame contains a list of all packages and modules that are defined by the project. Clicking on an entry will display its contents in the module contents frame. Clicking on a special entry, labeled "Everything," will display the contents of the entire project.

The module contents frame contains a list of every submodule, class, type, exception, function, and variable defined by a module or package. Clicking on an entry will display its documentation in the API documentation frame. Clicking on the name of the module, at the top of the frame, will display the documentation for the module itself.

The "frames" and "no frames" buttons below the top navigation bar can be used to control whether the table of contents is displayed or not.

The Navigation Bar

A navigation bar is located at the top and bottom of every page. It indicates what type of page you are currently viewing, and allows you to go to related pages. The following table describes the labels on the navigation bar. Note that not some labels (such as [Parent]) are not displayed on all pages.

Label Highlighted when... Links to...
[Parent] (never highlighted) the parent of the current package
[Package] viewing a package the package containing the current object
[Module] viewing a module the module containing the current object
[Class] viewing a class the class containing the current object
[Trees] viewing the trees page the trees page
[Index] viewing the index page the index page
[Help] viewing the help page the help page

The "show private" and "hide private" buttons below the top navigation bar can be used to control whether documentation for private objects is displayed. Private objects are usually defined as objects whose (short) names begin with a single underscore, but do not end with an underscore. For example, "_x", "__pprint", and "epydoc.epytext._tokenize" are private objects; but "re.sub", "__init__", and "type_" are not. However, if a module defines the "__all__" variable, then its contents are used to decide which objects are private.

A timestamp below the bottom navigation bar indicates when each page was last updated.

xappy-0.5/docs/api/identifier-index.html0000644000175000017500000017542111005555242020160 0ustar richardrichard Identifier Index
 
[frames] | no frames]

Identifier Index

[ 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

C

D

E

F

G

H

I

L

M

N

O

P

Q

R

S

T

U

V

X

Y

_



xappy-0.5/docs/api/index.html0000644000175000017500000000107711005555243016034 0ustar richardrichard xappy xappy-0.5/docs/api/module-tree.html0000644000175000017500000001431511005555242017145 0ustar richardrichard Module Hierarchy
 
[frames] | no frames]
[ Module Hierarchy | Class Hierarchy ]

Module Hierarchy

xappy-0.5/docs/api/redirect.html0000644000175000017500000000441411005555243016524 0ustar richardrichardEpydoc Redirect Page

Epydoc Auto-redirect page

When javascript is enabled, this page will redirect URLs of the form redirect.html#dotted.name to the documentation for the object with the given fully-qualified dotted name.

 

xappy-0.5/docs/api/toc-everything.html0000644000175000017500000001232411005555242017670 0ustar richardrichard Everything

Everything


All Classes

xappy.datastructures.Field
xappy.datastructures.ProcessedDocument
xappy.datastructures.UnprocessedDocument
xappy.errors.IndexerError
xappy.errors.SearchEngineError
xappy.errors.SearchError
xappy.errors.XapianError
xappy.fieldactions.ActionContext
xappy.fieldactions.FieldActions
xappy.fieldactions.SortableMarshaller
xappy.fieldmappings.FieldMappings
xappy.highlight.Highlighter
xappy.indexerconnection.FacetQueryTypeIter
xappy.indexerconnection.IndexerConnection
xappy.indexerconnection.PrefixedTermIter
xappy.indexerconnection.SynonymIter
xappy.replaylog.LoggedProxy
xappy.replaylog.LoggedProxyMethod
xappy.replaylog.NotifyingDeleteObject
xappy.replaylog.ReplayLog
xappy.schema.Schema
xappy.searchconnection.SearchConnection
xappy.searchconnection.SearchConnection.ExpandDecider
xappy.searchconnection.SearchResult
xappy.searchconnection.SearchResultIter
xappy.searchconnection.SearchResults

All Functions

xappy.marshall.date_to_string
xappy.marshall.float_to_string
xappy.memutils.get_physical_memory
xappy.parsedate.date_from_string
xappy.replaylog.log
xappy.replaylog.set_replay_path

All Variables

xappy.highlight.__test__
xappy.parsedate.yyyy_mm_dd_re
xappy.parsedate.yyyymmdd_re

xappy-0.5/docs/api/toc-xappy-module.html0000644000175000017500000000147611005555242020136 0ustar richardrichard xappy

Module xappy



xappy-0.5/docs/api/toc-xappy._checkxapian-module.html0000644000175000017500000000155511005555242022550 0ustar richardrichard _checkxapian

Module _checkxapian


Variables


xappy-0.5/docs/api/toc-xappy.datastructures-module.html0000644000175000017500000000226711005555242023211 0ustar richardrichard datastructures

Module datastructures


Classes

Field
ProcessedDocument
UnprocessedDocument

xappy-0.5/docs/api/toc-xappy.errors-module.html0000644000175000017500000000235511005555242021446 0ustar richardrichard errors

Module errors


Classes

IndexerError
SearchEngineError
SearchError
XapianError

xappy-0.5/docs/api/toc-xappy.fieldactions-module.html0000644000175000017500000000226111005555242022572 0ustar richardrichard fieldactions

Module fieldactions


Classes

ActionContext
FieldActions
SortableMarshaller

xappy-0.5/docs/api/toc-xappy.fieldmappings-module.html0000644000175000017500000000173011005555242022750 0ustar richardrichard fieldmappings

Module fieldmappings


Classes

FieldMappings

xappy-0.5/docs/api/toc-xappy.highlight-module.html0000644000175000017500000000210711005555242022074 0ustar richardrichard highlight

Module highlight


Classes

Highlighter

Variables

__test__

xappy-0.5/docs/api/toc-xappy.indexerconnection-module.html0000644000175000017500000000250511005555242023645 0ustar richardrichard indexerconnection

Module indexerconnection


Classes

FacetQueryTypeIter
IndexerConnection
PrefixedTermIter
SynonymIter

xappy-0.5/docs/api/toc-xappy.marshall-module.html0000644000175000017500000000207111005555242021730 0ustar richardrichard marshall

Module marshall


Functions

date_to_string
float_to_string

xappy-0.5/docs/api/toc-xappy.memutils-module.html0000644000175000017500000000173011005555242021765 0ustar richardrichard memutils

Module memutils


Functions

get_physical_memory

xappy-0.5/docs/api/toc-xappy.parsedate-module.html0000644000175000017500000000230211005555242022072 0ustar richardrichard parsedate

Module parsedate


Functions

date_from_string

Variables

yyyy_mm_dd_re
yyyymmdd_re

xappy-0.5/docs/api/toc-xappy.replaylog-module.html0000644000175000017500000000275611005555242022135 0ustar richardrichard replaylog

Module replaylog


Classes

LoggedProxy
LoggedProxyMethod
NotifyingDeleteObject
ReplayLog

Functions

log
set_replay_path

xappy-0.5/docs/api/toc-xappy.schema-module.html0000644000175000017500000000166511005555242021375 0ustar richardrichard schema

Module schema


Classes

Schema

xappy-0.5/docs/api/toc-xappy.searchconnection-module.html0000644000175000017500000000246511005555242023461 0ustar richardrichard searchconnection

Module searchconnection


Classes

SearchConnection
SearchResult
SearchResultIter
SearchResults

xappy-0.5/docs/api/toc.html0000644000175000017500000000655011005555242015512 0ustar richardrichard Table of Contents

Table of Contents


Everything

Modules

xappy
xappy.datastructures
xappy.errors
xappy.fieldactions
xappy.fieldmappings
xappy.highlight
xappy.indexerconnection
xappy.marshall
xappy.memutils
xappy.parsedate
xappy.replaylog
xappy.schema
xappy.searchconnection

xappy-0.5/docs/api/xappy-module.html0000644000175000017500000001560411005555242017351 0ustar richardrichard xappy
Package xappy
[frames] | no frames]

Package xappy

source code

Xappy.

See the accompanying documentation for details. In particular, there should be an accompanying file "introduction.html" (or "introduction.rst") which gives details of how to use the xappy package.




Version: 0.5

Submodules

xappy-0.5/docs/api/xappy-pysrc.html0000644000175000017500000003133511005555243017224 0ustar richardrichard xappy
Package xappy
[frames] | no frames]

Source Code for Package xappy

 1  #!/usr/bin/env python 
 2  # 
 3  # Copyright (C) 2007 Lemur Consulting Ltd 
 4  # 
 5  # This program is free software; you can redistribute it and/or modify 
 6  # it under the terms of the GNU General Public License as published by 
 7  # the Free Software Foundation; either version 2 of the License, or 
 8  # (at your option) any later version. 
 9  # 
10  # This program is distributed in the hope that it will be useful, 
11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
13  # GNU General Public License for more details. 
14  #  
15  # You should have received a copy of the GNU General Public License along 
16  # with this program; if not, write to the Free Software Foundation, Inc., 
17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
18  """Xappy. 
19   
20  See the accompanying documentation for details.  In particular, there should be 
21  an accompanying file "introduction.html" (or "introduction.rst") which gives 
22  details of how to use the xappy package. 
23   
24  """ 
25  __docformat__ = "restructuredtext en" 
26   
27  __version__ = '0.5' 
28   
29  import _checkxapian 
30  from datastructures import Field, UnprocessedDocument, ProcessedDocument 
31  from errors import * 
32  from fieldactions import FieldActions 
33  from indexerconnection import IndexerConnection 
34  from searchconnection import SearchConnection 
35  from replaylog import set_replay_path 
36   

xappy-0.5/docs/api/xappy._checkxapian-module.html0000644000175000017500000001264311005555242021765 0ustar richardrichard xappy._checkxapian
Package xappy :: Module _checkxapian
[frames] | no frames]

Module _checkxapian

source code

_checkxapian.py: Check the version of xapian used.

Raises an ImportError on import if the version used is too old to be used at all.



Variables
  min_xapian_version = (1, 0, 6)
  missing_features = {}
  versions = (1, 0, 6)
xappy-0.5/docs/api/xappy._checkxapian-pysrc.html0000644000175000017500000003315311005555243021640 0ustar richardrichard xappy._checkxapian
Package xappy :: Module _checkxapian
[frames] | no frames]

Source Code for Module xappy._checkxapian

 1  # Copyright (C) 2008 Lemur Consulting Ltd 
 2  # 
 3  # This program is free software; you can redistribute it and/or modify 
 4  # it under the terms of the GNU General Public License as published by 
 5  # the Free Software Foundation; either version 2 of the License, or 
 6  # (at your option) any later version. 
 7  # 
 8  # This program is distributed in the hope that it will be useful, 
 9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
11  # GNU General Public License for more details. 
12  #  
13  # You should have received a copy of the GNU General Public License along 
14  # with this program; if not, write to the Free Software Foundation, Inc., 
15  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
16  r"""_checkxapian.py: Check the version of xapian used. 
17   
18  Raises an ImportError on import if the version used is too old to be used at 
19  all. 
20   
21  """ 
22  __docformat__ = "restructuredtext en" 
23   
24  # The minimum version of xapian required to work at all. 
25  min_xapian_version = (1, 0, 6) 
26   
27  # Dictionary of features we can't support do to them being missing from the 
28  # available version of xapian. 
29  missing_features = {} 
30   
31  import xapian 
32   
33  versions = xapian.major_version(), xapian.minor_version(), xapian.revision() 
34   
35   
36  if versions < min_xapian_version: 
37      raise ImportError(""" 
38          Xapian Python bindings installed, but need at least version %d.%d.%d - got %s 
39          """.strip() % tuple(list(min_xapian_version) + [xapian.version_string()])) 
40   
41  if not hasattr(xapian, 'TermCountMatchSpy'): 
42      missing_features['tags'] = 1 
43  if not hasattr(xapian, 'CategorySelectMatchSpy'): 
44      missing_features['facets'] = 1 
45   

xappy-0.5/docs/api/xappy.datastructures-module.html0000644000175000017500000001206011005555242022416 0ustar richardrichard xappy.datastructures
Package xappy :: Module datastructures
[frames] | no frames]

Module datastructures

source code

datastructures.py: Datastructures for search engine core.

Classes
  Field
  UnprocessedDocument
A unprocessed document to be passed to the indexer.
  ProcessedDocument
A processed document, as stored in the index.
xappy-0.5/docs/api/xappy.datastructures-pysrc.html0000644000175000017500000020704711005555243022305 0ustar richardrichard xappy.datastructures
Package xappy :: Module datastructures
[frames] | no frames]

Source Code for Module xappy.datastructures

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright (C) 2007 Lemur Consulting Ltd 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  #  
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18  r"""datastructures.py: Datastructures for search engine core. 
 19   
 20  """ 
 21  __docformat__ = "restructuredtext en" 
 22   
 23  import errors 
 24  from replaylog import log 
 25  import xapian 
 26  import cPickle 
 27   
28 -class Field(object):
29 # Use __slots__ because we're going to have very many Field objects in 30 # typical usage. 31 __slots__ = 'name', 'value' 32
33 - def __init__(self, name, value):
34 self.name = name 35 self.value = value
36
37 - def __repr__(self):
38 return 'Field(%r, %r)' % (self.name, self.value)
39
40 -class UnprocessedDocument(object):
41 """A unprocessed document to be passed to the indexer. 42 43 This represents an item to be processed and stored in the search engine. 44 Each document will be processed by the indexer to generate a 45 ProcessedDocument, which can then be stored in the search engine index. 46 47 Note that some information in an UnprocessedDocument will not be 48 represented in the ProcessedDocument: therefore, it is not possible to 49 retrieve an UnprocessedDocument from the search engine index. 50 51 An unprocessed document is a simple container with two attributes: 52 53 - `fields` is a list of Field objects, or an iterator returning Field 54 objects. 55 - `id` is a string holding a unique identifier for the document (or 56 None to get the database to allocate a unique identifier automatically 57 when the document is added). 58 59 """ 60 61 __slots__ = 'id', 'fields',
62 - def __init__(self, id=None, fields=None):
63 self.id = id 64 if fields is None: 65 self.fields = [] 66 else: 67 self.fields = fields
68
69 - def __repr__(self):
70 return 'UnprocessedDocument(%r, %r)' % (self.id, self.fields)
71
72 -class ProcessedDocument(object):
73 """A processed document, as stored in the index. 74 75 This represents an item which is ready to be stored in the search engine, 76 or which has been returned by the search engine. 77 78 """ 79 80 __slots__ = '_doc', '_fieldmappings', '_data',
81 - def __init__(self, fieldmappings, xapdoc=None):
82 """Create a ProcessedDocument. 83 84 `fieldmappings` is the configuration from a database connection used lookup 85 the configuration to use to store each field. 86 87 If supplied, `xapdoc` is a Xapian document to store in the processed 88 document. Otherwise, a new Xapian document is created. 89 90 """ 91 if xapdoc is None: 92 self._doc = log(xapian.Document) 93 else: 94 self._doc = xapdoc 95 self._fieldmappings = fieldmappings 96 self._data = None
97
98 - def add_term(self, field, term, wdfinc=1, positions=None):
99 """Add a term to the document. 100 101 Terms are the main unit of information used for performing searches. 102 103 - `field` is the field to add the term to. 104 - `term` is the term to add. 105 - `wdfinc` is the value to increase the within-document-frequency 106 measure for the term by. 107 - `positions` is the positional information to add for the term. 108 This may be None to indicate that there is no positional information, 109 or may be an integer to specify one position, or may be a sequence of 110 integers to specify several positions. (Note that the wdf is not 111 increased automatically for each position: if you add a term at 7 112 positions, and the wdfinc value is 2, the total wdf for the term will 113 only be increased by 2, not by 14.) 114 115 """ 116 prefix = self._fieldmappings.get_prefix(field) 117 if len(term) > 0: 118 # We use the following check, rather than "isupper()" to ensure 119 # that we match the check performed by the queryparser, regardless 120 # of our locale. 121 if ord(term[0]) >= ord('A') and ord(term[0]) <= ord('Z'): 122 prefix = prefix + ':' 123 124 # Note - xapian currently restricts term lengths to about 248 125 # characters - except that zero bytes are encoded in two bytes, so 126 # in practice a term of length 125 characters could be too long. 127 # Xapian will give an error when commit() is called after such 128 # documents have been added to the database. 129 # As a simple workaround, we give an error here for terms over 220 130 # characters, which will catch most occurrences of the error early. 131 # 132 # In future, it might be good to change to a hashing scheme in this 133 # situation (or for terms over, say, 64 characters), where the 134 # characters after position 64 are hashed (we obviously need to do this 135 # hashing at search time, too). 136 if len(prefix + term) > 220: 137 raise errors.IndexerError("Field %r is too long: maximum length " 138 "220 - was %d (%r)" % 139 (field, len(prefix + term), 140 prefix + term)) 141 142 if positions is None: 143 self._doc.add_term(prefix + term, wdfinc) 144 elif isinstance(positions, int): 145 self._doc.add_posting(prefix + term, positions, wdfinc) 146 else: 147 self._doc.add_term(prefix + term, wdfinc) 148 for pos in positions: 149 self._doc.add_posting(prefix + term, pos, 0)
150
151 - def add_value(self, field, value, purpose=''):
152 """Add a value to the document. 153 154 Values are additional units of information used when performing 155 searches. Note that values are _not_ intended to be used to store 156 information for display in the search results - use the document data 157 for that. The intention is that as little information as possible is 158 stored in values, so that they can be accessed as quickly as possible 159 during the search operation. 160 161 Unlike terms, each document may have at most one value in each field 162 (whereas there may be an arbitrary number of terms in a given field). 163 If an attempt to add multiple values to a single field is made, only 164 the last value added will be stored. 165 166 """ 167 slot = self._fieldmappings.get_slot(field, purpose) 168 self._doc.add_value(slot, value)
169
170 - def get_value(self, field, purpose=''):
171 """Get a value from the document. 172 173 """ 174 slot = self._fieldmappings.get_slot(field, purpose) 175 return self._doc.get_value(slot)
176
177 - def prepare(self):
178 """Prepare the document for adding to a xapian database. 179 180 This updates the internal xapian document with any changes which have 181 been made, and then returns it. 182 183 """ 184 if self._data is not None: 185 self._doc.set_data(cPickle.dumps(self._data, 2)) 186 self._data = None 187 return self._doc
188
189 - def _get_data(self):
190 if self._data is None: 191 rawdata = self._doc.get_data() 192 if rawdata == '': 193 self._data = {} 194 else: 195 self._data = cPickle.loads(rawdata) 196 return self._data
197 - def _set_data(self, data):
198 if not isinstance(data, dict): 199 raise TypeError("Cannot set data to any type other than a dict") 200 self._data = data
201 data = property(_get_data, _set_data, doc= 202 """The data stored in this processed document. 203 204 This data is a dictionary of entries, where the key is a fieldname, and the 205 value is a list of strings. 206 207 """) 208
209 - def _get_id(self):
210 tl = self._doc.termlist() 211 try: 212 term = tl.skip_to('Q').term 213 if len(term) == 0 or term[0] != 'Q': 214 return None 215 except StopIteration: 216 return None 217 return term[1:]
218 - def _set_id(self, id):
219 tl = self._doc.termlist() 220 try: 221 term = tl.skip_to('Q').term 222 except StopIteration: 223 term = '' 224 if len(term) != 0 and term[0] == 'Q': 225 self._doc.remove_term(term) 226 if id is not None: 227 self._doc.add_term('Q' + id, 0)
228 id = property(_get_id, _set_id, doc= 229 """The unique ID for this document. 230 231 """) 232
233 - def __repr__(self):
234 return '<ProcessedDocument(%r)>' % (self.id)
235 236 if __name__ == '__main__': 237 import doctest, sys 238 doctest.testmod (sys.modules[__name__]) 239

xappy-0.5/docs/api/xappy.datastructures.Field-class.html0000644000175000017500000002231511005555242023264 0ustar richardrichard xappy.datastructures.Field
Package xappy :: Module datastructures :: Class Field
[frames] | no frames]

Class Field

source code

object --+
         |
        Field

Instance Methods
 
__init__(self, name, value)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
__repr__(self)
repr(x)
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __str__

Properties
  name
  value

Inherited from object: __class__

Method Details

__init__(self, name, value)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

__repr__(self)
(Representation operator)

source code 
repr(x)
Overrides: object.__repr__
(inherited documentation)

xappy-0.5/docs/api/xappy.datastructures.ProcessedDocument-class.html0000644000175000017500000004776511005555242025707 0ustar richardrichard xappy.datastructures.ProcessedDocument
Package xappy :: Module datastructures :: Class ProcessedDocument
[frames] | no frames]

Class ProcessedDocument

source code

object --+
         |
        ProcessedDocument
Known Subclasses:
searchconnection.SearchResult

A processed document, as stored in the index.

This represents an item which is ready to be stored in the search engine, or which has been returned by the search engine.



Instance Methods
 
__init__(self, fieldmappings, xapdoc=None)
Create a ProcessedDocument.
source code
 
add_term(self, field, term, wdfinc=1, positions=None)
Add a term to the document.
source code
 
add_value(self, field, value, purpose='')
Add a value to the document.
source code
 
get_value(self, field, purpose='')
Get a value from the document.
source code
 
prepare(self)
Prepare the document for adding to a xapian database.
source code
 
__repr__(self)
repr(x)
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __str__

Properties
  data
The data stored in this processed document.
  id
The unique ID for this document.

Inherited from object: __class__

Method Details

__init__(self, fieldmappings, xapdoc=None)
(Constructor)

source code 

Create a ProcessedDocument.

fieldmappings is the configuration from a database connection used lookup the configuration to use to store each field.

If supplied, xapdoc is a Xapian document to store in the processed document. Otherwise, a new Xapian document is created.

Overrides: object.__init__

add_term(self, field, term, wdfinc=1, positions=None)

source code 

Add a term to the document.

Terms are the main unit of information used for performing searches.

  • field is the field to add the term to.
  • term is the term to add.
  • wdfinc is the value to increase the within-document-frequency measure for the term by.
  • positions is the positional information to add for the term. This may be None to indicate that there is no positional information, or may be an integer to specify one position, or may be a sequence of integers to specify several positions. (Note that the wdf is not increased automatically for each position: if you add a term at 7 positions, and the wdfinc value is 2, the total wdf for the term will only be increased by 2, not by 14.)

add_value(self, field, value, purpose='')

source code 

Add a value to the document.

Values are additional units of information used when performing searches. Note that values are _not_ intended to be used to store information for display in the search results - use the document data for that. The intention is that as little information as possible is stored in values, so that they can be accessed as quickly as possible during the search operation.

Unlike terms, each document may have at most one value in each field (whereas there may be an arbitrary number of terms in a given field). If an attempt to add multiple values to a single field is made, only the last value added will be stored.

prepare(self)

source code 

Prepare the document for adding to a xapian database.

This updates the internal xapian document with any changes which have been made, and then returns it.

__repr__(self)
(Representation operator)

source code 
repr(x)
Overrides: object.__repr__
(inherited documentation)

Property Details

data

The data stored in this processed document.

This data is a dictionary of entries, where the key is a fieldname, and the value is a list of strings.

Get Method:
xappy.datastructures.ProcessedDocument._get_data(self)
Set Method:
xappy.datastructures.ProcessedDocument._set_data(self, data)

id

The unique ID for this document.
Get Method:
xappy.datastructures.ProcessedDocument._get_id(self)
Set Method:
xappy.datastructures.ProcessedDocument._set_id(self, id)

xappy-0.5/docs/api/xappy.datastructures.UnprocessedDocument-class.html0000644000175000017500000002505711005555242026240 0ustar richardrichard xappy.datastructures.UnprocessedDocument
Package xappy :: Module datastructures :: Class UnprocessedDocument
[frames] | no frames]

Class UnprocessedDocument

source code

object --+
         |
        UnprocessedDocument

A unprocessed document to be passed to the indexer.

This represents an item to be processed and stored in the search engine. Each document will be processed by the indexer to generate a ProcessedDocument, which can then be stored in the search engine index.

Note that some information in an UnprocessedDocument will not be represented in the ProcessedDocument: therefore, it is not possible to retrieve an UnprocessedDocument from the search engine index.

An unprocessed document is a simple container with two attributes:

  • fields is a list of Field objects, or an iterator returning Field objects.
  • id is a string holding a unique identifier for the document (or None to get the database to allocate a unique identifier automatically when the document is added).


Instance Methods
 
__init__(self, id=None, fields=None)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
__repr__(self)
repr(x)
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __str__

Properties
  fields
  id

Inherited from object: __class__

Method Details

__init__(self, id=None, fields=None)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

__repr__(self)
(Representation operator)

source code 
repr(x)
Overrides: object.__repr__
(inherited documentation)

xappy-0.5/docs/api/xappy.errors-module.html0000644000175000017500000001256411005555242020666 0ustar richardrichard xappy.errors
Package xappy :: Module errors
[frames] | no frames]

Module errors

source code

errors.py: Exceptions for the search engine core.

Classes
  SearchEngineError
Base class for exceptions thrown by the search engine.
  IndexerError
Class used to report errors relating to the indexing API.
  SearchError
Class used to report errors relating to the search API.
  XapianError
Base class for exceptions thrown by the xapian.
xappy-0.5/docs/api/xappy.errors-pysrc.html0000644000175000017500000005017511005555243020542 0ustar richardrichard xappy.errors
Package xappy :: Module errors
[frames] | no frames]

Source Code for Module xappy.errors

 1  #!/usr/bin/env python 
 2  # 
 3  # Copyright (C) 2007 Lemur Consulting Ltd 
 4  # 
 5  # This program is free software; you can redistribute it and/or modify 
 6  # it under the terms of the GNU General Public License as published by 
 7  # the Free Software Foundation; either version 2 of the License, or 
 8  # (at your option) any later version. 
 9  # 
10  # This program is distributed in the hope that it will be useful, 
11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
13  # GNU General Public License for more details. 
14  #  
15  # You should have received a copy of the GNU General Public License along 
16  # with this program; if not, write to the Free Software Foundation, Inc., 
17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
18  r"""errors.py: Exceptions for the search engine core. 
19   
20  """ 
21  __docformat__ = "restructuredtext en" 
22   
23 -class SearchEngineError(Exception):
24 r"""Base class for exceptions thrown by the search engine. 25 26 Any errors generated by xappy itself, or by xapian, will be instances of 27 this class or its subclasses. 28 29 """
30
31 -class IndexerError(SearchEngineError):
32 r"""Class used to report errors relating to the indexing API. 33 34 """
35
36 -class SearchError(SearchEngineError):
37 r"""Class used to report errors relating to the search API. 38 39 """
40 41
42 -class XapianError(SearchEngineError):
43 r"""Base class for exceptions thrown by the xapian. 44 45 Any errors generated by xapian will be instances of this class or its 46 subclasses. 47 48 """
49
51 """Add new base classes for all the xapian exceptions. 52 53 """ 54 import xapian 55 for name in ( 56 'AssertionError', 57 'DatabaseCorruptError', 58 'DatabaseCreateError', 59 'DatabaseError', 60 'DatabaseLockError', 61 'DatabaseModifiedError', 62 'DatabaseOpeningError', 63 'DatabaseVersionError', 64 'DocNotFoundError', 65 # We skip 'Error' because it inherits directly from exception 66 # and this causes problems with method resolution order. 67 # However, we probably don't need it anyway, because it's 68 # just a base class, and shouldn't ever actually be raised. 69 # Users can catch xappy.XapianError instead. 70 'FeatureUnavailableError', 71 'InternalError', 72 'InvalidArgumentError', 73 'InvalidOperationError', 74 'LogicError', 75 'NetworkError', 76 'NetworkTimeoutError', 77 'QueryParserError', 78 'RangeError', 79 'RuntimeError', 80 'UnimplementedError', 81 ): 82 xapian_exception = getattr(xapian, name, None) 83 if xapian_exception is not None: 84 xapian_exception.__bases__ += (XapianError, ) 85 globals()['Xapian' + name] = xapian_exception
86 87 _rebase_xapian_exceptions() 88

xappy-0.5/docs/api/xappy.errors.IndexerError-class.html0000644000175000017500000001422111005555242023105 0ustar richardrichard xappy.errors.IndexerError
Package xappy :: Module errors :: Class IndexerError
[frames] | no frames]

Class IndexerError

source code

              object --+            
                       |            
exceptions.BaseException --+        
                           |        
        exceptions.Exception --+    
                               |    
               SearchEngineError --+
                                   |
                                  IndexerError

Class used to report errors relating to the indexing API.

Instance Methods

Inherited from exceptions.Exception: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__

Inherited from object: __hash__, __reduce_ex__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

xappy-0.5/docs/api/xappy.errors.SearchEngineError-class.html0000644000175000017500000001457511005555242024056 0ustar richardrichard xappy.errors.SearchEngineError
Package xappy :: Module errors :: Class SearchEngineError
[frames] | no frames]

Class SearchEngineError

source code

              object --+        
                       |        
exceptions.BaseException --+    
                           |    
        exceptions.Exception --+
                               |
                              SearchEngineError
Known Subclasses:
IndexerError, SearchError, XapianError

Base class for exceptions thrown by the search engine.

Any errors generated by xappy itself, or by xapian, will be instances of this class or its subclasses.



Instance Methods

Inherited from exceptions.Exception: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__

Inherited from object: __hash__, __reduce_ex__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

xappy-0.5/docs/api/xappy.errors.SearchError-class.html0000644000175000017500000001421111005555242022713 0ustar richardrichard xappy.errors.SearchError
Package xappy :: Module errors :: Class SearchError
[frames] | no frames]

Class SearchError

source code

              object --+            
                       |            
exceptions.BaseException --+        
                           |        
        exceptions.Exception --+    
                               |    
               SearchEngineError --+
                                   |
                                  SearchError

Class used to report errors relating to the search API.

Instance Methods

Inherited from exceptions.Exception: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__

Inherited from object: __hash__, __reduce_ex__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

xappy-0.5/docs/api/xappy.errors.XapianError-class.html0000644000175000017500000001434111005555242022732 0ustar richardrichard xappy.errors.XapianError
Package xappy :: Module errors :: Class XapianError
[frames] | no frames]

Class XapianError

source code

              object --+            
                       |            
exceptions.BaseException --+        
                           |        
        exceptions.Exception --+    
                               |    
               SearchEngineError --+
                                   |
                                  XapianError

Base class for exceptions thrown by the xapian.

Any errors generated by xapian will be instances of this class or its subclasses.



Instance Methods

Inherited from exceptions.Exception: __init__, __new__

Inherited from exceptions.BaseException: __delattr__, __getattribute__, __getitem__, __getslice__, __reduce__, __repr__, __setattr__, __setstate__, __str__

Inherited from object: __hash__, __reduce_ex__

Properties

Inherited from exceptions.BaseException: args, message

Inherited from object: __class__

xappy-0.5/docs/api/xappy.fieldactions-module.html0000644000175000017500000001216411005555242022012 0ustar richardrichard xappy.fieldactions
Package xappy :: Module fieldactions
[frames] | no frames]

Module fieldactions

source code

fieldactions.py: Definitions and implementations of field actions.

Classes
  SortableMarshaller
Implementation of marshalling for sortable values.
  ActionContext
The context in which an action is performed.
  FieldActions
An object describing the actions to be performed on a field.
xappy-0.5/docs/api/xappy.fieldactions-pysrc.html0000644000175000017500000037532211005555243021676 0ustar richardrichard xappy.fieldactions
Package xappy :: Module fieldactions
[frames] | no frames]

Source Code for Module xappy.fieldactions

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright (C) 2007 Lemur Consulting Ltd 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  #  
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18  r"""fieldactions.py: Definitions and implementations of field actions. 
 19   
 20  """ 
 21  __docformat__ = "restructuredtext en" 
 22   
 23  import _checkxapian 
 24  import errors 
 25  import marshall 
 26  from replaylog import log 
 27  import xapian 
 28  import parsedate 
 29   
30 -def _act_store_content(fieldname, doc, value, context):
31 """Perform the STORE_CONTENT action. 32 33 """ 34 try: 35 fielddata = doc.data[fieldname] 36 except KeyError: 37 fielddata = [] 38 doc.data[fieldname] = fielddata 39 fielddata.append(value)
40
41 -def _act_index_exact(fieldname, doc, value, context):
42 """Perform the INDEX_EXACT action. 43 44 """ 45 doc.add_term(fieldname, value, 0)
46
47 -def _act_tag(fieldname, doc, value, context):
48 """Perform the TAG action. 49 50 """ 51 doc.add_term(fieldname, value.lower(), 0)
52
53 -def _act_facet(fieldname, doc, value, context, type=None):
54 """Perform the FACET action. 55 56 """ 57 if type is None or type == 'string': 58 value = value.lower() 59 doc.add_term(fieldname, value, 0) 60 serialiser = log(xapian.StringListSerialiser, 61 doc.get_value(fieldname, 'facet')) 62 serialiser.append(value) 63 doc.add_value(fieldname, serialiser.get(), 'facet') 64 else: 65 marshaller = SortableMarshaller() 66 fn = marshaller.get_marshall_function(fieldname, type) 67 doc.add_value(fieldname, fn(fieldname, value), 'facet')
68
69 -def _act_index_freetext(fieldname, doc, value, context, weight=1, 70 language=None, stop=None, spell=False, 71 nopos=False, 72 allow_field_specific=True, 73 search_by_default=True):
74 """Perform the INDEX_FREETEXT action. 75 76 """ 77 termgen = log(xapian.TermGenerator) 78 if language is not None: 79 termgen.set_stemmer(log(xapian.Stem, language)) 80 81 if stop is not None: 82 stopper = log(xapian.SimpleStopper) 83 for term in stop: 84 stopper.add (term) 85 termgen.set_stopper (stopper) 86 87 if spell: 88 termgen.set_database(context.index) 89 termgen.set_flags(termgen.FLAG_SPELLING) 90 91 termgen.set_document(doc._doc) 92 93 if search_by_default: 94 termgen.set_termpos(context.current_position) 95 # Store a copy of the field without a prefix, for non-field-specific 96 # searches. 97 if nopos: 98 termgen.index_text_without_positions(value, weight, '') 99 else: 100 termgen.index_text(value, weight, '') 101 102 if allow_field_specific: 103 # Store a second copy of the term with a prefix, for field-specific 104 # searches. 105 prefix = doc._fieldmappings.get_prefix(fieldname) 106 if len(prefix) != 0: 107 termgen.set_termpos(context.current_position) 108 if nopos: 109 termgen.index_text_without_positions(value, weight, prefix) 110 else: 111 termgen.index_text(value, weight, prefix) 112 113 # Add a gap between each field instance, so that phrase searches don't 114 # match across instances. 115 termgen.increase_termpos(10) 116 context.current_position = termgen.get_termpos()
117
118 -class SortableMarshaller(object):
119 """Implementation of marshalling for sortable values. 120 121 """
122 - def __init__(self, indexing=True):
123 if indexing: 124 self._err = errors.IndexerError 125 else: 126 self._err = errors.SearchError
127
128 - def marshall_string(self, fieldname, value):
129 """Marshall a value for sorting in lexicograpical order. 130 131 This returns the input as the output, since strings already sort in 132 lexicographical order. 133 134 """ 135 return value
136
137 - def marshall_float(self, fieldname, value):
138 """Marshall a value for sorting as a floating point value. 139 140 """ 141 # convert the value to a float 142 try: 143 value = float(value) 144 except ValueError: 145 raise self._err("Value supplied to field %r must be a " 146 "valid floating point number: was %r" % 147 (fieldname, value)) 148 return marshall.float_to_string(value)
149
150 - def marshall_date(self, fieldname, value):
151 """Marshall a value for sorting as a date. 152 153 """ 154 try: 155 value = parsedate.date_from_string(value) 156 except ValueError, e: 157 raise self._err("Value supplied to field %r must be a " 158 "valid date: was %r: error is '%s'" % 159 (fieldname, value, str(e))) 160 return marshall.date_to_string(value)
161
162 - def get_marshall_function(self, fieldname, sorttype):
163 """Get a function used to marshall values of a given sorttype. 164 165 """ 166 try: 167 return { 168 None: self.marshall_string, 169 'string': self.marshall_string, 170 'float': self.marshall_float, 171 'date': self.marshall_date, 172 }[sorttype] 173 except KeyError: 174 raise self._err("Unknown sort type %r for field %r" % 175 (sorttype, fieldname))
176 177
178 -def _act_sort_and_collapse(fieldname, doc, value, context, type=None):
179 """Perform the SORTABLE action. 180 181 """ 182 marshaller = SortableMarshaller() 183 fn = marshaller.get_marshall_function(fieldname, type) 184 value = fn(fieldname, value) 185 doc.add_value(fieldname, value, 'collsort')
186
187 -class ActionContext(object):
188 """The context in which an action is performed. 189 190 This is just used to pass term generators, word positions, and the like 191 around. 192 193 """
194 - def __init__(self, index):
195 self.current_language = None 196 self.current_position = 0 197 self.index = index
198
199 -class FieldActions(object):
200 """An object describing the actions to be performed on a field. 201 202 The supported actions are: 203 204 - `STORE_CONTENT`: store the unprocessed content of the field in the search 205 engine database. All fields which need to be displayed or used when 206 displaying the search results need to be given this action. 207 208 - `INDEX_EXACT`: index the exact content of the field as a single search 209 term. Fields whose contents need to be searchable as an "exact match" 210 need to be given this action. 211 212 - `INDEX_FREETEXT`: index the content of this field as text. The content 213 will be split into terms, allowing free text searching of the field. Four 214 optional parameters may be supplied: 215 216 - 'weight' is a multiplier to apply to the importance of the field. This 217 must be an integer, and the default value is 1. 218 - 'language' is the language to use when processing the field. This can 219 be expressed as an ISO 2-letter language code. The supported languages 220 are those supported by the xapian core in use. 221 - 'stop' is an iterable of stopwords to filter out of the generated 222 terms. Note that due to Xapian design, only non-positional terms are 223 affected, so this is of limited use. 224 - 'spell' is a boolean flag - if true, the contents of the field will be 225 used for spelling correction. 226 - 'nopos' is a boolean flag - if true, positional information is not 227 stored. 228 - 'allow_field_specific' is a boolean flag - if False, prevents terms with the field 229 prefix being generated. This means that searches specific to this 230 field will not work, and thus should only be used when only non-field 231 specific searches are desired. Defaults to True. 232 - 'search_by_default' is a boolean flag - if False, the field will not be 233 searched by non-field specific searches. If True, or omitted, the 234 field will be included in searches for non field-specific searches. 235 236 - `SORTABLE`: index the content of the field such that it can be used to 237 sort result sets. It also allows result sets to be restricted to those 238 documents with a field values in a given range. One optional parameter 239 may be supplied: 240 241 - 'type' is a value indicating how to sort the field. It has several 242 possible values: 243 244 - 'string' - sort in lexicographic (ie, alphabetical) order. 245 This is the default, used if no type is set. 246 - 'float' - treat the values as (decimal representations of) floating 247 point numbers, and sort in numerical order. The values in the field 248 must be valid floating point numbers (according to Python's float() 249 function). 250 - 'date' - sort in date order. The values must be valid dates (either 251 Python datetime.date objects, or ISO 8601 format (ie, YYYYMMDD or 252 YYYY-MM-DD). 253 254 - `COLLAPSE`: index the content of the field such that it can be used to 255 "collapse" result sets, such that only the highest result with each value 256 of the field will be returned. 257 258 - `TAG`: the field contains tags; these are strings, which will be matched 259 in a case insensitive way, but otherwise must be exact matches. Tag 260 fields can be searched for by making an explict query (ie, using 261 query_field(), but not with query_parse()). A list of the most frequent 262 tags in a result set can also be accessed easily. 263 264 - `FACET`: the field represents a classification facet; these are strings 265 which will be matched exactly, but a list of all the facets present in 266 the result set can also be accessed easily - in addition, a suitable 267 subset of the facets, and a selection of the facet values, present in the 268 result set can be calculated. One optional parameter may be supplied: 269 270 - 'type' is a value indicating the type of facet contained in the field: 271 272 - 'string' - the facet values are exact binary strings. 273 - 'float' - the facet values are floating point numbers. 274 275 """ 276 277 # See the class docstring for the meanings of the following constants. 278 STORE_CONTENT = 1 279 INDEX_EXACT = 2 280 INDEX_FREETEXT = 3 281 SORTABLE = 4 282 COLLAPSE = 5 283 TAG = 6 284 FACET = 7 285 286 # Sorting and collapsing store the data in a value, but the format depends 287 # on the sort type. Easiest way to implement is to treat them as the same 288 # action. 289 SORT_AND_COLLAPSE = -1 290 291 _unsupported_actions = [] 292 293 if 'tags' in _checkxapian.missing_features: 294 _unsupported_actions.append(TAG) 295 if 'facets' in _checkxapian.missing_features: 296 _unsupported_actions.append(FACET) 297
298 - def __init__(self, fieldname):
299 # Dictionary of actions, keyed by type. 300 self._actions = {} 301 self._fieldname = fieldname
302
303 - def add(self, field_mappings, action, **kwargs):
304 """Add an action to perform on a field. 305 306 """ 307 if action in self._unsupported_actions: 308 raise errors.IndexerError("Action unsupported with this release of xapian") 309 310 if action not in (FieldActions.STORE_CONTENT, 311 FieldActions.INDEX_EXACT, 312 FieldActions.INDEX_FREETEXT, 313 FieldActions.SORTABLE, 314 FieldActions.COLLAPSE, 315 FieldActions.TAG, 316 FieldActions.FACET, 317 ): 318 raise errors.IndexerError("Unknown field action: %r" % action) 319 320 info = self._action_info[action] 321 322 # Check parameter names 323 for key in kwargs.keys(): 324 if key not in info[1]: 325 raise errors.IndexerError("Unknown parameter name for action %r: %r" % (info[0], key)) 326 327 # Fields cannot be indexed both with "EXACT" and "FREETEXT": whilst we 328 # could implement this, the query parser wouldn't know what to do with 329 # searches. 330 if action == FieldActions.INDEX_EXACT: 331 if FieldActions.INDEX_FREETEXT in self._actions: 332 raise errors.IndexerError("Field %r is already marked for indexing " 333 "as free text: cannot mark for indexing " 334 "as exact text as well" % self._fieldname) 335 if action == FieldActions.INDEX_FREETEXT: 336 if FieldActions.INDEX_EXACT in self._actions: 337 raise errors.IndexerError("Field %r is already marked for indexing " 338 "as exact text: cannot mark for indexing " 339 "as free text as well" % self._fieldname) 340 341 # Fields cannot be indexed as more than one type for "SORTABLE": to 342 # implement this, we'd need to use a different prefix for each sortable 343 # type, but even then the search end wouldn't know what to sort on when 344 # searching. Also, if they're indexed as "COLLAPSE", the value must be 345 # stored in the right format for the type "SORTABLE". 346 if action == FieldActions.SORTABLE or action == FieldActions.COLLAPSE: 347 if action == FieldActions.COLLAPSE: 348 sorttype = None 349 else: 350 try: 351 sorttype = kwargs['type'] 352 except KeyError: 353 sorttype = 'string' 354 kwargs['type'] = sorttype 355 action = FieldActions.SORT_AND_COLLAPSE 356 357 try: 358 oldsortactions = self._actions[FieldActions.SORT_AND_COLLAPSE] 359 except KeyError: 360 oldsortactions = () 361 362 if len(oldsortactions) > 0: 363 for oldsortaction in oldsortactions: 364 oldsorttype = oldsortaction['type'] 365 366 if sorttype == oldsorttype or oldsorttype is None: 367 # Use new type 368 self._actions[action] = [] 369 elif sorttype is None: 370 # Use old type 371 return 372 else: 373 raise errors.IndexerError("Field %r is already marked for " 374 "sorting, with a different " 375 "sort type" % self._fieldname) 376 377 if 'prefix' in info[3]: 378 field_mappings.add_prefix(self._fieldname) 379 if 'slot' in info[3]: 380 purposes = info[3]['slot'] 381 if isinstance(purposes, basestring): 382 field_mappings.add_slot(self._fieldname, purposes) 383 else: 384 slotnum = None 385 for purpose in purposes: 386 slotnum = field_mappings.get_slot(self._fieldname, purpose) 387 if slotnum is not None: 388 break 389 for purpose in purposes: 390 field_mappings.add_slot(self._fieldname, purpose, slotnum=slotnum) 391 392 # Make an entry for the action 393 if action not in self._actions: 394 self._actions[action] = [] 395 396 # Check for repetitions of actions 397 for old_action in self._actions[action]: 398 if old_action == kwargs: 399 return 400 401 # Append the action to the list of actions 402 self._actions[action].append(kwargs)
403
404 - def perform(self, doc, value, context):
405 """Perform the actions on the field. 406 407 - `doc` is a ProcessedDocument to store the result of the actions in. 408 - `value` is a string holding the value of the field. 409 - `context` is an ActionContext object used to keep state in. 410 411 """ 412 for type, actionlist in self._actions.iteritems(): 413 info = self._action_info[type] 414 for kwargs in actionlist: 415 info[2](self._fieldname, doc, value, context, **kwargs)
416 417 _action_info = { 418 STORE_CONTENT: ('STORE_CONTENT', (), _act_store_content, {}, ), 419 INDEX_EXACT: ('INDEX_EXACT', (), _act_index_exact, {'prefix': True}, ), 420 INDEX_FREETEXT: ('INDEX_FREETEXT', ('weight', 'language', 'stop', 'spell', 'nopos', 'allow_field_specific', 'search_by_default', ), 421 _act_index_freetext, {'prefix': True, }, ), 422 SORTABLE: ('SORTABLE', ('type', ), None, {'slot': 'collsort',}, ), 423 COLLAPSE: ('COLLAPSE', (), None, {'slot': 'collsort',}, ), 424 TAG: ('TAG', (), _act_tag, {'prefix': True,}, ), 425 FACET: ('FACET', ('type', ), _act_facet, {'prefix': True, 'slot': 'facet',}, ), 426 427 SORT_AND_COLLAPSE: ('SORT_AND_COLLAPSE', ('type', ), _act_sort_and_collapse, {'slot': 'collsort',}, ), 428 }
429 430 if __name__ == '__main__': 431 import doctest, sys 432 doctest.testmod (sys.modules[__name__]) 433

xappy-0.5/docs/api/xappy.fieldactions.ActionContext-class.html0000644000175000017500000001672411005555242024421 0ustar richardrichard xappy.fieldactions.ActionContext
Package xappy :: Module fieldactions :: Class ActionContext
[frames] | no frames]

Class ActionContext

source code

object --+
         |
        ActionContext

The context in which an action is performed.

This is just used to pass term generators, word positions, and the like around.



Instance Methods
 
__init__(self, index)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, index)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

xappy-0.5/docs/api/xappy.fieldactions.FieldActions-class.html0000644000175000017500000004161611005555242024201 0ustar richardrichard xappy.fieldactions.FieldActions
Package xappy :: Module fieldactions :: Class FieldActions
[frames] | no frames]

Class FieldActions

source code

object --+
         |
        FieldActions

An object describing the actions to be performed on a field.

The supported actions are:

  • STORE_CONTENT: store the unprocessed content of the field in the search engine database. All fields which need to be displayed or used when displaying the search results need to be given this action.
  • INDEX_EXACT: index the exact content of the field as a single search term. Fields whose contents need to be searchable as an "exact match" need to be given this action.
  • INDEX_FREETEXT: index the content of this field as text. The content will be split into terms, allowing free text searching of the field. Four optional parameters may be supplied:
    • 'weight' is a multiplier to apply to the importance of the field. This must be an integer, and the default value is 1.
    • 'language' is the language to use when processing the field. This can be expressed as an ISO 2-letter language code. The supported languages are those supported by the xapian core in use.
    • 'stop' is an iterable of stopwords to filter out of the generated terms. Note that due to Xapian design, only non-positional terms are affected, so this is of limited use.
    • 'spell' is a boolean flag - if true, the contents of the field will be used for spelling correction.
    • 'nopos' is a boolean flag - if true, positional information is not stored.
    • 'allow_field_specific' is a boolean flag - if False, prevents terms with the field prefix being generated. This means that searches specific to this field will not work, and thus should only be used when only non-field specific searches are desired. Defaults to True.
    • 'search_by_default' is a boolean flag - if False, the field will not be searched by non-field specific searches. If True, or omitted, the field will be included in searches for non field-specific searches.
  • SORTABLE: index the content of the field such that it can be used to sort result sets. It also allows result sets to be restricted to those documents with a field values in a given range. One optional parameter may be supplied:
    • 'type' is a value indicating how to sort the field. It has several possible values:
      • 'string' - sort in lexicographic (ie, alphabetical) order. This is the default, used if no type is set.
      • 'float' - treat the values as (decimal representations of) floating point numbers, and sort in numerical order. The values in the field must be valid floating point numbers (according to Python's float() function).
      • 'date' - sort in date order. The values must be valid dates (either Python datetime.date objects, or ISO 8601 format (ie, YYYYMMDD or YYYY-MM-DD).
  • COLLAPSE: index the content of the field such that it can be used to "collapse" result sets, such that only the highest result with each value of the field will be returned.
  • TAG: the field contains tags; these are strings, which will be matched in a case insensitive way, but otherwise must be exact matches. Tag fields can be searched for by making an explict query (ie, using query_field(), but not with query_parse()). A list of the most frequent tags in a result set can also be accessed easily.
  • FACET: the field represents a classification facet; these are strings which will be matched exactly, but a list of all the facets present in the result set can also be accessed easily - in addition, a suitable subset of the facets, and a selection of the facet values, present in the result set can be calculated. One optional parameter may be supplied:
    • 'type' is a value indicating the type of facet contained in the field:
      • 'string' - the facet values are exact binary strings.
      • 'float' - the facet values are floating point numbers.


Instance Methods
 
__init__(self, fieldname)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
add(self, field_mappings, action, **kwargs)
Add an action to perform on a field.
source code
 
perform(self, doc, value, context)
Perform the actions on the field.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Class Variables
  STORE_CONTENT = 1
  INDEX_EXACT = 2
  INDEX_FREETEXT = 3
  SORTABLE = 4
  COLLAPSE = 5
  TAG = 6
  FACET = 7
  SORT_AND_COLLAPSE = -1
Properties

Inherited from object: __class__

Method Details

__init__(self, fieldname)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

perform(self, doc, value, context)

source code 

Perform the actions on the field.

  • doc is a ProcessedDocument to store the result of the actions in.
  • value is a string holding the value of the field.
  • context is an ActionContext object used to keep state in.

xappy-0.5/docs/api/xappy.fieldactions.SortableMarshaller-class.html0000644000175000017500000002732311005555243025423 0ustar richardrichard xappy.fieldactions.SortableMarshaller
Package xappy :: Module fieldactions :: Class SortableMarshaller
[frames] | no frames]

Class SortableMarshaller

source code

object --+
         |
        SortableMarshaller

Implementation of marshalling for sortable values.

Instance Methods
 
__init__(self, indexing=True)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
marshall_string(self, fieldname, value)
Marshall a value for sorting in lexicograpical order.
source code
 
marshall_float(self, fieldname, value)
Marshall a value for sorting as a floating point value.
source code
 
marshall_date(self, fieldname, value)
Marshall a value for sorting as a date.
source code
 
get_marshall_function(self, fieldname, sorttype)
Get a function used to marshall values of a given sorttype.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, indexing=True)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

marshall_string(self, fieldname, value)

source code 

Marshall a value for sorting in lexicograpical order.

This returns the input as the output, since strings already sort in lexicographical order.


xappy-0.5/docs/api/xappy.fieldmappings-module.html0000644000175000017500000001075111005555242022170 0ustar richardrichard xappy.fieldmappings
Package xappy :: Module fieldmappings
[frames] | no frames]

Module fieldmappings

source code

fieldmappings.py: Mappings from field names to term prefixes, etc.

Classes
  FieldMappings
Mappings from field names to term prefixes, slot values, etc.
xappy-0.5/docs/api/xappy.fieldmappings-pysrc.html0000644000175000017500000010741211005555243022045 0ustar richardrichard xappy.fieldmappings
Package xappy :: Module fieldmappings
[frames] | no frames]

Source Code for Module xappy.fieldmappings

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright (C) 2007 Lemur Consulting Ltd 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  #  
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18  r"""fieldmappings.py: Mappings from field names to term prefixes, etc. 
 19   
 20  """ 
 21  __docformat__ = "restructuredtext en" 
 22   
 23  import cPickle as _cPickle 
 24   
25 -class FieldMappings(object):
26 """Mappings from field names to term prefixes, slot values, etc. 27 28 The following mappings are maintained: 29 30 - a mapping from field name to the string prefix to insert at the start of 31 terms. 32 - a mapping from field name to the slot numbers to store the field contents 33 in. 34 35 """ 36 __slots__ = '_prefixes', '_prefixcount', '_slots', '_slotcount', 37
38 - def __init__(self, serialised=None):
39 """Create a new field mapping object, or unserialise a saved one. 40 41 """ 42 if serialised is not None: 43 (self._prefixes, self._prefixcount, 44 self._slots, self._slotcount) = _cPickle.loads(serialised) 45 else: 46 self._prefixes = {} 47 self._prefixcount = 0 48 self._slots = {} 49 self._slotcount = 0
50
51 - def _genPrefix(self):
52 """Generate a previously unused prefix. 53 54 Prefixes are uppercase letters, and start with 'X' (this is a Xapian 55 convention, for compatibility with other Xapian tools: other starting 56 letters are reserved for special meanings): 57 58 >>> maps = FieldMappings() 59 >>> maps._genPrefix() 60 'XA' 61 >>> maps._genPrefix() 62 'XB' 63 >>> [maps._genPrefix() for i in xrange(60)] 64 ['XC', 'XD', 'XE', 'XF', 'XG', 'XH', 'XI', 'XJ', 'XK', 'XL', 'XM', 'XN', 'XO', 'XP', 'XQ', 'XR', 'XS', 'XT', 'XU', 'XV', 'XW', 'XX', 'XY', 'XZ', 'XAA', 'XBA', 'XCA', 'XDA', 'XEA', 'XFA', 'XGA', 'XHA', 'XIA', 'XJA', 'XKA', 'XLA', 'XMA', 'XNA', 'XOA', 'XPA', 'XQA', 'XRA', 'XSA', 'XTA', 'XUA', 'XVA', 'XWA', 'XXA', 'XYA', 'XZA', 'XAB', 'XBB', 'XCB', 'XDB', 'XEB', 'XFB', 'XGB', 'XHB', 'XIB', 'XJB'] 65 >>> maps = FieldMappings() 66 >>> [maps._genPrefix() for i in xrange(27*26 + 5)][-10:] 67 ['XVZ', 'XWZ', 'XXZ', 'XYZ', 'XZZ', 'XAAA', 'XBAA', 'XCAA', 'XDAA', 'XEAA'] 68 """ 69 res = [] 70 self._prefixcount += 1 71 num = self._prefixcount 72 while num != 0: 73 ch = (num - 1) % 26 74 res.append(chr(ch + ord('A'))) 75 num -= ch 76 num = num // 26 77 return 'X' + ''.join(res)
78
79 - def get_fieldname_from_prefix(self, prefix):
80 """Get a fieldname from a prefix. 81 82 If the prefix is not found, return None. 83 84 """ 85 for key, val in self._prefixes.iteritems(): 86 if val == prefix: 87 return key 88 return None
89
90 - def get_prefix(self, fieldname):
91 """Get the prefix used for a given field name. 92 93 """ 94 return self._prefixes[fieldname]
95
96 - def get_slot(self, fieldname, purpose):
97 """Get the slot number used for a given field name and purpose. 98 99 """ 100 return self._slots[(fieldname, purpose)]
101
102 - def add_prefix(self, fieldname):
103 """Allocate a prefix for the given field. 104 105 If a prefix is already allocated for this field, this has no effect. 106 107 """ 108 if fieldname in self._prefixes: 109 return 110 self._prefixes[fieldname] = self._genPrefix()
111
112 - def add_slot(self, fieldname, purpose, slotnum=None):
113 """Allocate a slot number for the given field and purpose. 114 115 If a slot number is already allocated for this field and purpose, this 116 has no effect. 117 118 Returns the slot number allocated for the field and purpose (whether 119 newly allocated, or previously allocated). 120 121 If `slotnum` is supplied, the number contained in it is used to 122 allocate the new slot, instead of allocating a new number. No checks 123 will be made to ensure that the slot number doesn't collide with 124 existing (or later allocated) numbers: the main purpose of this 125 parameter is to share allocations - ie, to collide deliberately. 126 127 """ 128 try: 129 return self._slots[(fieldname, purpose)] 130 except KeyError: 131 pass 132 133 if slotnum is None: 134 self._slots[(fieldname, purpose)] = self._slotcount 135 self._slotcount += 1 136 return self._slotcount - 1 137 else: 138 self._slots[(fieldname, purpose)] = slotnum 139 return slotnum
140
141 - def serialise(self):
142 """Serialise the field mappings to a string. 143 144 This can be unserialised by passing the result of this method to the 145 constructor of a new FieldMappings object. 146 147 """ 148 return _cPickle.dumps((self._prefixes, 149 self._prefixcount, 150 self._slots, 151 self._slotcount, 152 ), 2)
153

xappy-0.5/docs/api/xappy.fieldmappings.FieldMappings-class.html0000644000175000017500000004016211005555243024531 0ustar richardrichard xappy.fieldmappings.FieldMappings
Package xappy :: Module fieldmappings :: Class FieldMappings
[frames] | no frames]

Class FieldMappings

source code

object --+
         |
        FieldMappings

Mappings from field names to term prefixes, slot values, etc.

The following mappings are maintained:

  • a mapping from field name to the string prefix to insert at the start of terms.
  • a mapping from field name to the slot numbers to store the field contents in.


Instance Methods
 
__init__(self, serialised=None)
Create a new field mapping object, or unserialise a saved one.
source code
 
get_fieldname_from_prefix(self, prefix)
Get a fieldname from a prefix.
source code
 
get_prefix(self, fieldname)
Get the prefix used for a given field name.
source code
 
get_slot(self, fieldname, purpose)
Get the slot number used for a given field name and purpose.
source code
 
add_prefix(self, fieldname)
Allocate a prefix for the given field.
source code
 
add_slot(self, fieldname, purpose, slotnum=None)
Allocate a slot number for the given field and purpose.
source code
 
serialise(self)
Serialise the field mappings to a string.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, serialised=None)
(Constructor)

source code 
Create a new field mapping object, or unserialise a saved one.
Overrides: object.__init__

get_fieldname_from_prefix(self, prefix)

source code 

Get a fieldname from a prefix.

If the prefix is not found, return None.

add_prefix(self, fieldname)

source code 

Allocate a prefix for the given field.

If a prefix is already allocated for this field, this has no effect.

add_slot(self, fieldname, purpose, slotnum=None)

source code 

Allocate a slot number for the given field and purpose.

If a slot number is already allocated for this field and purpose, this has no effect.

Returns the slot number allocated for the field and purpose (whether newly allocated, or previously allocated).

If slotnum is supplied, the number contained in it is used to allocate the new slot, instead of allocating a new number. No checks will be made to ensure that the slot number doesn't collide with existing (or later allocated) numbers: the main purpose of this parameter is to share allocations - ie, to collide deliberately.

serialise(self)

source code 

Serialise the field mappings to a string.

This can be unserialised by passing the result of this method to the constructor of a new FieldMappings object.


xappy-0.5/docs/api/xappy.highlight-module.html0000644000175000017500000001656111005555242021322 0ustar richardrichard xappy.highlight
Package xappy :: Module highlight
[frames] | no frames]

Module highlight

source code

highlight.py: Highlight and summarise text.

Classes
  Highlighter
Class for highlighting text and creating contextual summaries.
Variables
  __test__ = {'apostrophes': '\n\n >>> hl = Highlighter(\'en\...
Variables Details

__test__

Value:
{'apostrophes': '''

    >>> hl = Highlighter(\'en\')
    >>> hl.makeSample("A boring start.  Hello world\'s indeed.  A bori\
ng end.", [\'world\'], 40, (\'<\', \'>\'))
    "A boring start.  Hello <world\'s> indeed..."

    ''',
...

xappy-0.5/docs/api/xappy.highlight-pysrc.html0000644000175000017500000020312511005555243021170 0ustar richardrichard xappy.highlight
Package xappy :: Module highlight
[frames] | no frames]

Source Code for Module xappy.highlight

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright (C) 2007 Lemur Consulting Ltd 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  # 
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18  r"""highlight.py: Highlight and summarise text. 
 19   
 20  """ 
 21  __docformat__ = "restructuredtext en" 
 22   
 23  import re 
 24  import xapian 
 25   
26 -class Highlighter(object):
27 """Class for highlighting text and creating contextual summaries. 28 29 >>> hl = Highlighter("en") 30 >>> hl.makeSample('Hello world.', ['world']) 31 'Hello world.' 32 >>> hl.highlight('Hello world', ['world'], ('<', '>')) 33 'Hello <world>' 34 35 """ 36 37 # split string into words, spaces, punctuation and markup tags 38 _split_re = re.compile(r'<\w+[^>]*>|</\w+>|[\w\']+|\s+|[^\w\'\s<>/]+') 39
40 - def __init__(self, language_code='en', stemmer=None):
41 """Create a new highlighter for the specified language. 42 43 """ 44 if stemmer is not None: 45 self.stem = stemmer 46 else: 47 self.stem = xapian.Stem(language_code)
48
49 - def _split_text(self, text, strip_tags=False):
50 """Split some text into words and non-words. 51 52 - `text` is the text to process. It may be a unicode object or a utf-8 53 encoded simple string. 54 - `strip_tags` is a flag - False to keep tags, True to strip all tags 55 from the output. 56 57 Returns a list of utf-8 encoded simple strings. 58 59 """ 60 if isinstance(text, unicode): 61 text = text.encode('utf-8') 62 63 words = self._split_re.findall(text) 64 if strip_tags: 65 return [w for w in words if w[0] != '<'] 66 else: 67 return words
68
69 - def _strip_prefix(self, term):
70 """Strip the prefix off a term. 71 72 Prefixes are any initial capital letters, with the exception that R always 73 ends a prefix, even if followed by capital letters. 74 75 >>> hl = Highlighter("en") 76 >>> print hl._strip_prefix('hello') 77 hello 78 >>> print hl._strip_prefix('Rhello') 79 hello 80 >>> print hl._strip_prefix('XARHello') 81 Hello 82 >>> print hl._strip_prefix('XAhello') 83 hello 84 >>> print hl._strip_prefix('XAh') 85 h 86 >>> print hl._strip_prefix('XA') 87 <BLANKLINE> 88 89 """ 90 for p in xrange(len(term)): 91 if term[p].islower(): 92 return term[p:] 93 elif term[p] == 'R': 94 return term[p+1:] 95 return ''
96
97 - def _query_to_stemmed_words(self, query):
98 """Convert a query to a list of stemmed words. 99 100 - `query` is the query to parse: it may be xapian.Query object, or a 101 sequence of terms. 102 103 """ 104 if isinstance(query, xapian.Query): 105 return [self._strip_prefix(t) for t in query] 106 else: 107 return [self.stem(q.lower()) for q in query]
108 109
110 - def makeSample(self, text, query, maxlen=600, hl=None):
111 """Make a contextual summary from the supplied text. 112 113 This basically works by splitting the text into phrases, counting the query 114 terms in each, and keeping those with the most. 115 116 Any markup tags in the text will be stripped. 117 118 `text` is the source text to summarise. 119 `query` is either a Xapian query object or a list of (unstemmed) term strings. 120 `maxlen` is the maximum length of the generated summary. 121 `hl` is a pair of strings to insert around highlighted terms, e.g. ('<b>', '</b>') 122 123 """ 124 125 # coerce maxlen into an int, otherwise truncation doesn't happen 126 maxlen = int(maxlen) 127 128 words = self._split_text(text, True) 129 terms = self._query_to_stemmed_words(query) 130 131 # build blocks delimited by puncuation, and count matching words in each block 132 # blocks[n] is a block [firstword, endword, charcount, termcount, selected] 133 blocks = [] 134 start = end = count = blockchars = 0 135 136 while end < len(words): 137 blockchars += len(words[end]) 138 if words[end].isalnum(): 139 if self.stem(words[end].lower()) in terms: 140 count += 1 141 end += 1 142 elif words[end] in ',.;:?!\n': 143 end += 1 144 blocks.append([start, end, blockchars, count, False]) 145 start = end 146 blockchars = 0 147 count = 0 148 else: 149 end += 1 150 if start != end: 151 blocks.append([start, end, blockchars, count, False]) 152 if len(blocks) == 0: 153 return '' 154 155 # select high-scoring blocks first, down to zero-scoring 156 chars = 0 157 for count in xrange(3, -1, -1): 158 for b in blocks: 159 if b[3] >= count: 160 b[4] = True 161 chars += b[2] 162 if chars >= maxlen: break 163 if chars >= maxlen: break 164 165 # assemble summary 166 words2 = [] 167 lastblock = -1 168 for i, b in enumerate(blocks): 169 if b[4]: 170 if i != lastblock + 1: 171 words2.append('..') 172 words2.extend(words[b[0]:b[1]]) 173 lastblock = i 174 175 if not blocks[-1][4]: 176 words2.append('..') 177 178 # trim down to maxlen 179 l = 0 180 for i in xrange (len (words2)): 181 l += len (words2[i]) 182 if l >= maxlen: 183 words2[i:] = ['..'] 184 break 185 186 if hl is None: 187 return ''.join(words2) 188 else: 189 return self._hl(words2, terms, hl)
190
191 - def highlight(self, text, query, hl, strip_tags=False):
192 """Add highlights (string prefix/postfix) to a string. 193 194 `text` is the source to highlight. 195 `query` is either a Xapian query object or a list of (unstemmed) term strings. 196 `hl` is a pair of highlight strings, e.g. ('<i>', '</i>') 197 `strip_tags` strips HTML markout iff True 198 199 >>> hl = Highlighter() 200 >>> qp = xapian.QueryParser() 201 >>> q = qp.parse_query('cat dog') 202 >>> tags = ('[[', ']]') 203 >>> hl.highlight('The cat went Dogging; but was <i>dog tired</i>.', q, tags) 204 'The [[cat]] went [[Dogging]]; but was <i>[[dog]] tired</i>.' 205 206 """ 207 words = self._split_text(text, strip_tags) 208 terms = self._query_to_stemmed_words(query) 209 return self._hl(words, terms, hl)
210
211 - def _hl(self, words, terms, hl):
212 """Add highlights to a list of words. 213 214 `words` is the list of words and non-words to be highlighted.. 215 `terms` is the list of stemmed words to look for. 216 217 """ 218 for i, w in enumerate(words): 219 # HACK - more forgiving about stemmed terms 220 wl = w.lower() 221 if wl in terms or self.stem (wl) in terms: 222 words[i] = ''.join((hl[0], w, hl[1])) 223 224 return ''.join(words)
225 226 227 __test__ = { 228 'no_punc': r''' 229 230 Test the highlighter's behaviour when there is no punctuation in the sample 231 text (regression test - used to return no output): 232 >>> hl = Highlighter("en") 233 >>> hl.makeSample('Hello world', ['world']) 234 'Hello world' 235 236 ''', 237 238 'stem_levels': r''' 239 240 Test highlighting of words, and how it works with stemming: 241 >>> hl = Highlighter("en") 242 243 # "word" and "wording" stem to "word", so the following 4 calls all return 244 # the same thing 245 >>> hl.makeSample('Hello. word. wording. wordinging.', ['word'], hl='<>') 246 'Hello. <word>. <wording>. wordinging.' 247 >>> hl.highlight('Hello. word. wording. wordinging.', ['word'], '<>') 248 'Hello. <word>. <wording>. wordinging.' 249 >>> hl.makeSample('Hello. word. wording. wordinging.', ['wording'], hl='<>') 250 'Hello. <word>. <wording>. wordinging.' 251 >>> hl.highlight('Hello. word. wording. wordinging.', ['wording'], '<>') 252 'Hello. <word>. <wording>. wordinging.' 253 254 # "wordinging" stems to "wording", so only the last two words are 255 # highlighted for this one. 256 >>> hl.makeSample('Hello. word. wording. wordinging.', ['wordinging'], hl='<>') 257 'Hello. word. <wording>. <wordinging>.' 258 >>> hl.highlight('Hello. word. wording. wordinging.', ['wordinging'], '<>') 259 'Hello. word. <wording>. <wordinging>.' 260 ''', 261 262 'supplied_stemmer': r''' 263 264 Test behaviour if we pass in our own stemmer: 265 >>> stem = xapian.Stem('en') 266 >>> hl = Highlighter(stemmer=stem) 267 >>> hl.highlight('Hello. word. wording. wordinging.', ['word'], '<>') 268 'Hello. <word>. <wording>. wordinging.' 269 270 ''', 271 272 'unicode': r''' 273 274 Test behaviour if we pass in unicode input: 275 >>> hl = Highlighter('en') 276 >>> hl.highlight(u'Hello\xf3. word. wording. wordinging.', ['word'], '<>') 277 'Hello\xc3\xb3. <word>. <wording>. wordinging.' 278 279 ''', 280 281 'no_sample': r''' 282 283 Test behaviour if we pass in unicode input: 284 >>> hl = Highlighter('en') 285 >>> hl.makeSample(u'', ['word']) 286 '' 287 288 ''', 289 290 'short_samples': r''' 291 292 >>> hl = Highlighter('en') 293 >>> hl.makeSample("A boring start. Hello world indeed. A boring end.", ['hello'], 20, ('<', '>')) 294 '.. <Hello> world ..' 295 >>> hl.makeSample("A boring start. Hello world indeed. A boring end.", ['hello'], 40, ('<', '>')) 296 'A boring start. <Hello> world indeed...' 297 >>> hl.makeSample("A boring start. Hello world indeed. A boring end.", ['boring'], 40, ('<', '>')) 298 'A <boring> start... A <boring> end.' 299 300 ''', 301 302 'apostrophes': r''' 303 304 >>> hl = Highlighter('en') 305 >>> hl.makeSample("A boring start. Hello world's indeed. A boring end.", ['world'], 40, ('<', '>')) 306 "A boring start. Hello <world's> indeed..." 307 308 ''', 309 310 } 311 312 if __name__ == '__main__': 313 import doctest, sys 314 doctest.testmod (sys.modules[__name__]) 315

xappy-0.5/docs/api/xappy.highlight.Highlighter-class.html0000644000175000017500000003313411005555243023373 0ustar richardrichard xappy.highlight.Highlighter
Package xappy :: Module highlight :: Class Highlighter
[frames] | no frames]

Class Highlighter

source code

object --+
         |
        Highlighter

Class for highlighting text and creating contextual summaries.

>>> hl = Highlighter("en")
>>> hl.makeSample('Hello world.', ['world'])
'Hello world.'
>>> hl.highlight('Hello world', ['world'], ('<', '>'))
'Hello <world>'


Instance Methods
 
__init__(self, language_code='en', stemmer=None)
Create a new highlighter for the specified language.
source code
 
makeSample(self, text, query, maxlen=600, hl=None)
Make a contextual summary from the supplied text.
source code
 
highlight(self, text, query, hl, strip_tags=False)
Add highlights (string prefix/postfix) to a string.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, language_code='en', stemmer=None)
(Constructor)

source code 
Create a new highlighter for the specified language.
Overrides: object.__init__

makeSample(self, text, query, maxlen=600, hl=None)

source code 

Make a contextual summary from the supplied text.

This basically works by splitting the text into phrases, counting the query terms in each, and keeping those with the most.

Any markup tags in the text will be stripped.

text is the source text to summarise. query is either a Xapian query object or a list of (unstemmed) term strings. maxlen is the maximum length of the generated summary. hl is a pair of strings to insert around highlighted terms, e.g. ('<b>', '</b>')

highlight(self, text, query, hl, strip_tags=False)

source code 

Add highlights (string prefix/postfix) to a string.

text is the source to highlight. query is either a Xapian query object or a list of (unstemmed) term strings. hl is a pair of highlight strings, e.g. ('<i>', '</i>') strip_tags strips HTML markout iff True

>>> hl = Highlighter()
>>> qp = xapian.QueryParser()
>>> q = qp.parse_query('cat dog')
>>> tags = ('[[', ']]')
>>> hl.highlight('The cat went Dogging; but was <i>dog tired</i>.', q, tags)
'The [[cat]] went [[Dogging]]; but was <i>[[dog]] tired</i>.'

xappy-0.5/docs/api/xappy.indexerconnection-module.html0000644000175000017500000001276011005555242023066 0ustar richardrichard xappy.indexerconnection
Package xappy :: Module indexerconnection
[frames] | no frames]

Module indexerconnection

source code

indexerconnection.py: A connection to the search engine for indexing.

Classes
  IndexerConnection
A connection to the search engine for indexing.
  PrefixedTermIter
Iterate through all the terms with a given prefix.
  SynonymIter
Iterate through a list of synonyms.
  FacetQueryTypeIter
Iterate through all the query types and their associated facets.
xappy-0.5/docs/api/xappy.indexerconnection-pysrc.html0000644000175000017500000070756511005555243022760 0ustar richardrichard xappy.indexerconnection
Package xappy :: Module indexerconnection
[frames] | no frames]

Source Code for Module xappy.indexerconnection

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright (C) 2007 Lemur Consulting Ltd 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  #  
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18  r"""indexerconnection.py: A connection to the search engine for indexing. 
 19   
 20  """ 
 21  __docformat__ = "restructuredtext en" 
 22   
 23  import _checkxapian 
 24  import cPickle 
 25  import xapian 
 26   
 27  from datastructures import * 
 28  import errors 
 29  from fieldactions import * 
 30  import fieldmappings 
 31  import memutils 
 32  from replaylog import log 
 33   
34 -class IndexerConnection(object):
35 """A connection to the search engine for indexing. 36 37 """ 38
39 - def __init__(self, indexpath):
40 """Create a new connection to the index. 41 42 There may only be one indexer connection for a particular database open 43 at a given time. Therefore, if a connection to the database is already 44 open, this will raise a xapian.DatabaseLockError. 45 46 If the database doesn't already exist, it will be created. 47 48 """ 49 self._index = log(xapian.WritableDatabase, indexpath, xapian.DB_CREATE_OR_OPEN) 50 self._indexpath = indexpath 51 52 # Read existing actions. 53 self._field_actions = {} 54 self._field_mappings = fieldmappings.FieldMappings() 55 self._facet_hierarchy = {} 56 self._facet_query_table = {} 57 self._next_docid = 0 58 self._config_modified = False 59 self._load_config() 60 61 # Set management of the memory used. 62 # This can be removed once Xapian implements this itself. 63 self._mem_buffered = 0 64 self.set_max_mem_use()
65
66 - def set_max_mem_use(self, max_mem=None, max_mem_proportion=None):
67 """Set the maximum memory to use. 68 69 This call allows the amount of memory to use to buffer changes to be 70 set. This will affect the speed of indexing, but should not result in 71 other changes to the indexing. 72 73 Note: this is an approximate measure - the actual amount of memory used 74 max exceed the specified amount. Also, note that future versions of 75 xapian are likely to implement this differently, so this setting may be 76 entirely ignored. 77 78 The absolute amount of memory to use (in bytes) may be set by setting 79 max_mem. Alternatively, the proportion of the available memory may be 80 set by setting max_mem_proportion (this should be a value between 0 and 81 1). 82 83 Setting too low a value will result in excessive flushing, and very 84 slow indexing. Setting too high a value will result in excessive 85 buffering, leading to swapping, and very slow indexing. 86 87 A reasonable default for max_mem_proportion for a system which is 88 dedicated to indexing is probably 0.5: if other tasks are also being 89 performed on the system, the value should be lowered. 90 91 """ 92 if self._index is None: 93 raise errors.IndexerError("IndexerConnection has been closed") 94 if max_mem is not None and max_mem_proportion is not None: 95 raise errors.IndexerError("Only one of max_mem and " 96 "max_mem_proportion may be specified") 97 98 if max_mem is None and max_mem_proportion is None: 99 self._max_mem = None 100 101 if max_mem_proportion is not None: 102 physmem = memutils.get_physical_memory() 103 if physmem is not None: 104 max_mem = int(physmem * max_mem_proportion) 105 106 self._max_mem = max_mem
107
108 - def _store_config(self):
109 """Store the configuration for the database. 110 111 Currently, this stores the configuration in a file in the database 112 directory, so changes to it are not protected by transactions. When 113 support is available in xapian for storing metadata associated with 114 databases. this will be used instead of a file. 115 116 """ 117 assert self._index is not None 118 119 config_str = cPickle.dumps(( 120 self._field_actions, 121 self._field_mappings.serialise(), 122 self._facet_hierarchy, 123 self._facet_query_table, 124 self._next_docid, 125 ), 2) 126 log(self._index.set_metadata, '_xappy_config', config_str) 127 128 self._config_modified = False
129
130 - def _load_config(self):
131 """Load the configuration for the database. 132 133 """ 134 assert self._index is not None 135 136 config_str = log(self._index.get_metadata, '_xappy_config') 137 if len(config_str) == 0: 138 return 139 140 try: 141 (self._field_actions, mappings, self._facet_hierarchy, self._facet_query_table, self._next_docid) = cPickle.loads(config_str) 142 except ValueError: 143 # Backwards compatibility - configuration used to lack _facet_hierarchy and _facet_query_table 144 (self._field_actions, mappings, self._next_docid) = cPickle.loads(config_str) 145 self._facet_hierarchy = {} 146 self._facet_query_table = {} 147 self._field_mappings = fieldmappings.FieldMappings(mappings) 148 149 self._config_modified = False
150
151 - def _allocate_id(self):
152 """Allocate a new ID. 153 154 """ 155 while True: 156 idstr = "%x" % self._next_docid 157 self._next_docid += 1 158 if not self._index.term_exists('Q' + idstr): 159 break 160 self._config_modified = True 161 return idstr
162
163 - def add_field_action(self, fieldname, fieldtype, **kwargs):
164 """Add an action to be performed on a field. 165 166 Note that this change to the configuration will not be preserved on 167 disk until the next call to flush(). 168 169 """ 170 if self._index is None: 171 raise errors.IndexerError("IndexerConnection has been closed") 172 if fieldname in self._field_actions: 173 actions = self._field_actions[fieldname] 174 else: 175 actions = FieldActions(fieldname) 176 self._field_actions[fieldname] = actions 177 actions.add(self._field_mappings, fieldtype, **kwargs) 178 self._config_modified = True
179
180 - def clear_field_actions(self, fieldname):
181 """Clear all actions for the specified field. 182 183 This does not report an error if there are already no actions for the 184 specified field. 185 186 Note that this change to the configuration will not be preserved on 187 disk until the next call to flush(). 188 189 """ 190 if self._index is None: 191 raise errors.IndexerError("IndexerConnection has been closed") 192 if fieldname in self._field_actions: 193 del self._field_actions[fieldname] 194 self._config_modified = True
195
196 - def get_fields_with_actions(self):
197 """Get a list of field names which have actions defined. 198 199 """ 200 if self._index is None: 201 raise errors.IndexerError("IndexerConnection has been closed") 202 return self._field_actions.keys()
203
204 - def process(self, document):
205 """Process an UnprocessedDocument with the settings in this database. 206 207 The resulting ProcessedDocument is returned. 208 209 Note that this processing will be automatically performed if an 210 UnprocessedDocument is supplied to the add() or replace() methods of 211 IndexerConnection. This method is exposed to allow the processing to 212 be performed separately, which may be desirable if you wish to manually 213 modify the processed document before adding it to the database, or if 214 you want to split processing of documents from adding documents to the 215 database for performance reasons. 216 217 """ 218 if self._index is None: 219 raise errors.IndexerError("IndexerConnection has been closed") 220 result = ProcessedDocument(self._field_mappings) 221 result.id = document.id 222 context = ActionContext(self._index) 223 224 for field in document.fields: 225 try: 226 actions = self._field_actions[field.name] 227 except KeyError: 228 # If no actions are defined, just ignore the field. 229 continue 230 actions.perform(result, field.value, context) 231 232 return result
233
234 - def _get_bytes_used_by_doc_terms(self, xapdoc):
235 """Get an estimate of the bytes used by the terms in a document. 236 237 (This is a very rough estimate.) 238 239 """ 240 count = 0 241 for item in xapdoc.termlist(): 242 # The term may also be stored in the spelling correction table, so 243 # double the amount used. 244 count += len(item.term) * 2 245 246 # Add a few more bytes for holding the wdf, and other bits and 247 # pieces. 248 count += 8 249 250 # Empirical observations indicate that about 5 times as much memory as 251 # the above calculation predicts is used for buffering in practice. 252 return count * 5
253
254 - def add(self, document):
255 """Add a new document to the search engine index. 256 257 If the document has a id set, and the id already exists in 258 the database, an exception will be raised. Use the replace() method 259 instead if you wish to overwrite documents. 260 261 Returns the id of the newly added document (making up a new 262 unique ID if no id was set). 263 264 The supplied document may be an instance of UnprocessedDocument, or an 265 instance of ProcessedDocument. 266 267 """ 268 if self._index is None: 269 raise errors.IndexerError("IndexerConnection has been closed") 270 if not hasattr(document, '_doc'): 271 # It's not a processed document. 272 document = self.process(document) 273 274 # Ensure that we have a id 275 orig_id = document.id 276 if orig_id is None: 277 id = self._allocate_id() 278 document.id = id 279 else: 280 id = orig_id 281 if self._index.term_exists('Q' + id): 282 raise errors.IndexerError("Document ID of document supplied to add() is not unique.") 283 284 # Add the document. 285 xapdoc = document.prepare() 286 self._index.add_document(xapdoc) 287 288 if self._max_mem is not None: 289 self._mem_buffered += self._get_bytes_used_by_doc_terms(xapdoc) 290 if self._mem_buffered > self._max_mem: 291 self.flush() 292 293 if id is not orig_id: 294 document.id = orig_id 295 return id
296
297 - def replace(self, document):
298 """Replace a document in the search engine index. 299 300 If the document does not have a id set, an exception will be 301 raised. 302 303 If the document has a id set, and the id does not already 304 exist in the database, this method will have the same effect as add(). 305 306 """ 307 if self._index is None: 308 raise errors.IndexerError("IndexerConnection has been closed") 309 if not hasattr(document, '_doc'): 310 # It's not a processed document. 311 document = self.process(document) 312 313 # Ensure that we have a id 314 id = document.id 315 if id is None: 316 raise errors.IndexerError("No document ID set for document supplied to replace().") 317 318 xapdoc = document.prepare() 319 self._index.replace_document('Q' + id, xapdoc) 320 321 if self._max_mem is not None: 322 self._mem_buffered += self._get_bytes_used_by_doc_terms(xapdoc) 323 if self._mem_buffered > self._max_mem: 324 self.flush()
325
326 - def _make_synonym_key(self, original, field):
327 """Make a synonym key (ie, the term or group of terms to store in 328 xapian). 329 330 """ 331 if field is not None: 332 prefix = self._field_mappings.get_prefix(field) 333 else: 334 prefix = '' 335 original = original.lower() 336 # Add the prefix to the start of each word. 337 return ' '.join((prefix + word for word in original.split(' ')))
338
339 - def add_synonym(self, original, synonym, field=None, 340 original_field=None, synonym_field=None):
341 """Add a synonym to the index. 342 343 - `original` is the word or words which will be synonym expanded in 344 searches (if multiple words are specified, each word should be 345 separated by a single space). 346 - `synonym` is a synonym for `original`. 347 - `field` is the field which the synonym is specific to. If no field 348 is specified, the synonym will be used for searches which are not 349 specific to any particular field. 350 351 """ 352 if self._index is None: 353 raise errors.IndexerError("IndexerConnection has been closed") 354 if original_field is None: 355 original_field = field 356 if synonym_field is None: 357 synonym_field = field 358 key = self._make_synonym_key(original, original_field) 359 # FIXME - this only works for exact fields which have no upper case 360 # characters, or single words 361 value = self._make_synonym_key(synonym, synonym_field) 362 self._index.add_synonym(key, value)
363
364 - def remove_synonym(self, original, synonym, field=None):
365 """Remove a synonym from the index. 366 367 - `original` is the word or words which will be synonym expanded in 368 searches (if multiple words are specified, each word should be 369 separated by a single space). 370 - `synonym` is a synonym for `original`. 371 - `field` is the field which this synonym is specific to. If no field 372 is specified, the synonym will be used for searches which are not 373 specific to any particular field. 374 375 """ 376 if self._index is None: 377 raise errors.IndexerError("IndexerConnection has been closed") 378 key = self._make_synonym_key(original, field) 379 self._index.remove_synonym(key, synonym.lower())
380
381 - def clear_synonyms(self, original, field=None):
382 """Remove all synonyms for a word (or phrase). 383 384 - `field` is the field which this synonym is specific to. If no field 385 is specified, the synonym will be used for searches which are not 386 specific to any particular field. 387 388 """ 389 if self._index is None: 390 raise errors.IndexerError("IndexerConnection has been closed") 391 key = self._make_synonym_key(original, field) 392 self._index.clear_synonyms(key)
393
394 - def _assert_facet(self, facet):
395 """Raise an error if facet is not a declared facet field. 396 397 """ 398 for action in self._field_actions[facet]._actions: 399 if action == FieldActions.FACET: 400 return 401 raise errors.IndexerError("Field %r is not indexed as a facet" % facet)
402
403 - def add_subfacet(self, subfacet, facet):
404 """Add a subfacet-facet relationship to the facet hierarchy. 405 406 Any existing relationship for that subfacet is replaced. 407 408 Raises a KeyError if either facet or subfacet is not a field, 409 and an IndexerError if either facet or subfacet is not a facet field. 410 """ 411 if self._index is None: 412 raise errors.IndexerError("IndexerConnection has been closed") 413 self._assert_facet(facet) 414 self._assert_facet(subfacet) 415 self._facet_hierarchy[subfacet] = facet 416 self._config_modified = True
417
418 - def remove_subfacet(self, subfacet):
419 """Remove any existing facet hierarchy relationship for a subfacet. 420 421 """ 422 if self._index is None: 423 raise errors.IndexerError("IndexerConnection has been closed") 424 if subfacet in self._facet_hierarchy: 425 del self._facet_hierarchy[subfacet] 426 self._config_modified = True
427
428 - def get_subfacets(self, facet):
429 """Get a list of subfacets of a facet. 430 431 """ 432 if self._index is None: 433 raise errors.IndexerError("IndexerConnection has been closed") 434 return [k for k, v in self._facet_hierarchy.iteritems() if v == facet]
435 436 FacetQueryType_Preferred = 1; 437 FacetQueryType_Never = 2;
438 - def set_facet_for_query_type(self, query_type, facet, association):
439 """Set the association between a query type and a facet. 440 441 The value of `association` must be one of 442 IndexerConnection.FacetQueryType_Preferred, 443 IndexerConnection.FacetQueryType_Never or None. A value of None removes 444 any previously set association. 445 446 """ 447 if self._index is None: 448 raise errors.IndexerError("IndexerConnection has been closed") 449 if query_type is None: 450 raise errors.IndexerError("Cannot set query type information for None") 451 self._assert_facet(facet) 452 if query_type not in self._facet_query_table: 453 self._facet_query_table[query_type] = {} 454 if association is None: 455 if facet in self._facet_query_table[query_type]: 456 del self._facet_query_table[query_type][facet] 457 else: 458 self._facet_query_table[query_type][facet] = association; 459 if self._facet_query_table[query_type] == {}: 460 del self._facet_query_table[query_type] 461 self._config_modified = True
462
463 - def get_facets_for_query_type(self, query_type, association):
464 """Get the set of facets associated with a query type. 465 466 Only those facets associated with the query type in the specified 467 manner are returned; `association` must be one of 468 IndexerConnection.FacetQueryType_Preferred or 469 IndexerConnection.FacetQueryType_Never. 470 471 If the query type has no facets associated with it, None is returned. 472 473 """ 474 if self._index is None: 475 raise errors.IndexerError("IndexerConnection has been closed") 476 if query_type not in self._facet_query_table: 477 return None 478 facet_dict = self._facet_query_table[query_type] 479 return set([facet for facet, assoc in facet_dict.iteritems() if assoc == association])
480
481 - def set_metadata(self, key, value):
482 """Set an item of metadata stored in the connection. 483 484 The value supplied will be returned by subsequent calls to 485 get_metadata() which use the same key. 486 487 Keys with a leading underscore are reserved for internal use - you 488 should not use such keys unless you really know what you are doing. 489 490 This will store the value supplied in the database. It will not be 491 visible to readers (ie, search connections) until after the next flush. 492 493 The key is limited to about 200 characters (the same length as a term 494 is limited to). The value can be several megabytes in size. 495 496 To remove an item of metadata, simply call this with a `value` 497 parameter containing an empty string. 498 499 """ 500 if self._index is None: 501 raise errors.IndexerError("IndexerConnection has been closed") 502 if not hasattr(self._index, 'set_metadata'): 503 raise errors.IndexerError("Version of xapian in use does not support metadata") 504 log(self._index.set_metadata, key, value)
505
506 - def get_metadata(self, key):
507 """Get an item of metadata stored in the connection. 508 509 This returns a value stored by a previous call to set_metadata. 510 511 If the value is not found, this will return the empty string. 512 513 """ 514 if self._index is None: 515 raise errors.IndexerError("IndexerConnection has been closed") 516 if not hasattr(self._index, 'get_metadata'): 517 raise errors.IndexerError("Version of xapian in use does not support metadata") 518 return log(self._index.get_metadata, key)
519
520 - def delete(self, id):
521 """Delete a document from the search engine index. 522 523 If the id does not already exist in the database, this method 524 will have no effect (and will not report an error). 525 526 """ 527 if self._index is None: 528 raise errors.IndexerError("IndexerConnection has been closed") 529 self._index.delete_document('Q' + id)
530
531 - def flush(self):
532 """Apply recent changes to the database. 533 534 If an exception occurs, any changes since the last call to flush() may 535 be lost. 536 537 """ 538 if self._index is None: 539 raise errors.IndexerError("IndexerConnection has been closed") 540 if self._config_modified: 541 self._store_config() 542 self._index.flush() 543 self._mem_buffered = 0
544
545 - def close(self):
546 """Close the connection to the database. 547 548 It is important to call this method before allowing the class to be 549 garbage collected, because it will ensure that any un-flushed changes 550 will be flushed. It also ensures that the connection is cleaned up 551 promptly. 552 553 No other methods may be called on the connection after this has been 554 called. (It is permissible to call close() multiple times, but 555 only the first call will have any effect.) 556 557 If an exception occurs, the database will be closed, but changes since 558 the last call to flush may be lost. 559 560 """ 561 if self._index is None: 562 return 563 try: 564 self.flush() 565 finally: 566 # There is currently no "close()" method for xapian databases, so 567 # we have to rely on the garbage collector. Since we never copy 568 # the _index property out of this class, there should be no cycles, 569 # so the standard python implementation should garbage collect 570 # _index straight away. A close() method is planned to be added to 571 # xapian at some point - when it is, we should call it here to make 572 # the code more robust. 573 self._index = None 574 self._indexpath = None 575 self._field_actions = None 576 self._config_modified = False
577
578 - def get_doccount(self):
579 """Count the number of documents in the database. 580 581 This count will include documents which have been added or removed but 582 not yet flushed(). 583 584 """ 585 if self._index is None: 586 raise errors.IndexerError("IndexerConnection has been closed") 587 return self._index.get_doccount()
588
589 - def iterids(self):
590 """Get an iterator which returns all the ids in the database. 591 592 The unqiue_ids are currently returned in binary lexicographical sort 593 order, but this should not be relied on. 594 595 """ 596 if self._index is None: 597 raise errors.IndexerError("IndexerConnection has been closed") 598 return PrefixedTermIter('Q', self._index.allterms())
599
600 - def get_document(self, id):
601 """Get the document with the specified unique ID. 602 603 Raises a KeyError if there is no such document. Otherwise, it returns 604 a ProcessedDocument. 605 606 """ 607 if self._index is None: 608 raise errors.IndexerError("IndexerConnection has been closed") 609 postlist = self._index.postlist('Q' + id) 610 try: 611 plitem = postlist.next() 612 except StopIteration: 613 # Unique ID not found 614 raise KeyError('Unique ID %r not found' % id) 615 try: 616 postlist.next() 617 raise errors.IndexerError("Multiple documents " #pragma: no cover 618 "found with same unique ID") 619 except StopIteration: 620 # Only one instance of the unique ID found, as it should be. 621 pass 622 623 result = ProcessedDocument(self._field_mappings) 624 result.id = id 625 result._doc = self._index.get_document(plitem.docid) 626 return result
627
628 - def iter_synonyms(self, prefix=""):
629 """Get an iterator over the synonyms. 630 631 - `prefix`: if specified, only synonym keys with this prefix will be 632 returned. 633 634 The iterator returns 2-tuples, in which the first item is the key (ie, 635 a 2-tuple holding the term or terms which will be synonym expanded, 636 followed by the fieldname specified (or None if no fieldname)), and the 637 second item is a tuple of strings holding the synonyms for the first 638 item. 639 640 These return values are suitable for the dict() builtin, so you can 641 write things like: 642 643 >>> conn = IndexerConnection('foo') 644 >>> conn.add_synonym('foo', 'bar') 645 >>> conn.add_synonym('foo bar', 'baz') 646 >>> conn.add_synonym('foo bar', 'foo baz') 647 >>> dict(conn.iter_synonyms()) 648 {('foo', None): ('bar',), ('foo bar', None): ('baz', 'foo baz')} 649 650 """ 651 if self._index is None: 652 raise errors.IndexerError("IndexerConnection has been closed") 653 return SynonymIter(self._index, self._field_mappings, prefix)
654
655 - def iter_subfacets(self):
656 """Get an iterator over the facet hierarchy. 657 658 The iterator returns 2-tuples, in which the first item is the 659 subfacet and the second item is its parent facet. 660 661 The return values are suitable for the dict() builtin, for example: 662 663 >>> conn = IndexerConnection('db') 664 >>> conn.add_field_action('foo', FieldActions.FACET) 665 >>> conn.add_field_action('bar', FieldActions.FACET) 666 >>> conn.add_field_action('baz', FieldActions.FACET) 667 >>> conn.add_subfacet('foo', 'bar') 668 >>> conn.add_subfacet('baz', 'bar') 669 >>> dict(conn.iter_subfacets()) 670 {'foo': 'bar', 'baz': 'bar'} 671 672 """ 673 if self._index is None: 674 raise errors.IndexerError("IndexerConnection has been closed") 675 if 'facets' in _checkxapian.missing_features: 676 raise errors.IndexerError("Facets unsupported with this release of xapian") 677 return self._facet_hierarchy.iteritems()
678
679 - def iter_facet_query_types(self, association):
680 """Get an iterator over query types and their associated facets. 681 682 Only facets associated with the query types in the specified manner 683 are returned; `association` must be one of IndexerConnection.FacetQueryType_Preferred 684 or IndexerConnection.FacetQueryType_Never. 685 686 The iterator returns 2-tuples, in which the first item is the query 687 type and the second item is the associated set of facets. 688 689 The return values are suitable for the dict() builtin, for example: 690 691 >>> conn = IndexerConnection('db') 692 >>> conn.add_field_action('foo', FieldActions.FACET) 693 >>> conn.add_field_action('bar', FieldActions.FACET) 694 >>> conn.add_field_action('baz', FieldActions.FACET) 695 >>> conn.set_facet_for_query_type('type1', 'foo', conn.FacetQueryType_Preferred) 696 >>> conn.set_facet_for_query_type('type1', 'bar', conn.FacetQueryType_Never) 697 >>> conn.set_facet_for_query_type('type1', 'baz', conn.FacetQueryType_Never) 698 >>> conn.set_facet_for_query_type('type2', 'bar', conn.FacetQueryType_Preferred) 699 >>> dict(conn.iter_facet_query_types(conn.FacetQueryType_Preferred)) 700 {'type1': set(['foo']), 'type2': set(['bar'])} 701 >>> dict(conn.iter_facet_query_types(conn.FacetQueryType_Never)) 702 {'type1': set(['bar', 'baz'])} 703 704 """ 705 if self._index is None: 706 raise errors.IndexerError("IndexerConnection has been closed") 707 if 'facets' in _checkxapian.missing_features: 708 raise errors.IndexerError("Facets unsupported with this release of xapian") 709 return FacetQueryTypeIter(self._facet_query_table, association)
710
711 -class PrefixedTermIter(object):
712 """Iterate through all the terms with a given prefix. 713 714 """
715 - def __init__(self, prefix, termiter):
716 """Initialise the prefixed term iterator. 717 718 - `prefix` is the prefix to return terms for. 719 - `termiter` is a xapian TermIterator, which should be at its start. 720 721 """ 722 723 # The algorithm used in next() currently only works for single 724 # character prefixes, so assert that the prefix is single character. 725 # To deal with multicharacter prefixes, we need to check for terms 726 # which have a starting prefix equal to that given, but then have a 727 # following uppercase alphabetic character, indicating that the actual 728 # prefix is longer than the target prefix. We then need to skip over 729 # these. Not too hard to implement, but we don't need it yet. 730 assert(len(prefix) == 1) 731 732 self._started = False 733 self._prefix = prefix 734 self._prefixlen = len(prefix) 735 self._termiter = termiter
736
737 - def __iter__(self):
738 return self
739
740 - def next(self):
741 """Get the next term with the specified prefix. 742 743 """ 744 if not self._started: 745 term = self._termiter.skip_to(self._prefix).term 746 self._started = True 747 else: 748 term = self._termiter.next().term 749 if len(term) < self._prefixlen or term[:self._prefixlen] != self._prefix: 750 raise StopIteration 751 return term[self._prefixlen:]
752 753
754 -class SynonymIter(object):
755 """Iterate through a list of synonyms. 756 757 """
758 - def __init__(self, index, field_mappings, prefix):
759 """Initialise the synonym iterator. 760 761 - `index` is the index to get the synonyms from. 762 - `field_mappings` is the FieldMappings object for the iterator. 763 - `prefix` is the prefix to restrict the returned synonyms to. 764 765 """ 766 self._index = index 767 self._field_mappings = field_mappings 768 self._syniter = self._index.synonym_keys(prefix)
769
770 - def __iter__(self):
771 return self
772
773 - def next(self):
774 """Get the next synonym. 775 776 """ 777 synkey = self._syniter.next() 778 pos = 0 779 for char in synkey: 780 if char.isupper(): pos += 1 781 else: break 782 if pos == 0: 783 fieldname = None 784 terms = synkey 785 else: 786 prefix = synkey[:pos] 787 fieldname = self._field_mappings.get_fieldname_from_prefix(prefix) 788 terms = ' '.join((term[pos:] for term in synkey.split(' '))) 789 synval = tuple(self._index.synonyms(synkey)) 790 return ((terms, fieldname), synval)
791
792 -class FacetQueryTypeIter(object):
793 """Iterate through all the query types and their associated facets. 794 795 """
796 - def __init__(self, facet_query_table, association):
797 """Initialise the query type facet iterator. 798 799 Only facets associated with each query type in the specified 800 manner are returned (`association` must be one of 801 IndexerConnection.FacetQueryType_Preferred or 802 IndexerConnection.FacetQueryType_Never). 803 804 """ 805 self._table_iter = facet_query_table.iteritems() 806 self._association = association
807
808 - def __iter__(self):
809 return self
810
811 - def next(self):
812 """Get the next (query type, facet set) 2-tuple. 813 814 """ 815 query_type, facet_dict = self._table_iter.next() 816 facet_list = [facet for facet, association in facet_dict.iteritems() if association == self._association] 817 if len(facet_list) == 0: 818 return self.next() 819 return (query_type, set(facet_list))
820 821 if __name__ == '__main__': 822 import doctest, sys 823 doctest.testmod (sys.modules[__name__]) 824

xappy-0.5/docs/api/xappy.indexerconnection.FacetQueryTypeIter-class.html0000644000175000017500000002203211005555243026435 0ustar richardrichard xappy.indexerconnection.FacetQueryTypeIter
Package xappy :: Module indexerconnection :: Class FacetQueryTypeIter
[frames] | no frames]

Class FacetQueryTypeIter

source code

object --+
         |
        FacetQueryTypeIter

Iterate through all the query types and their associated facets.

Instance Methods
 
__init__(self, facet_query_table, association)
Initialise the query type facet iterator.
source code
 
__iter__(self) source code
 
next(self)
Get the next (query type, facet set) 2-tuple.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, facet_query_table, association)
(Constructor)

source code 

Initialise the query type facet iterator.

Only facets associated with each query type in the specified manner are returned (association must be one of IndexerConnection.FacetQueryType_Preferred or IndexerConnection.FacetQueryType_Never).

Overrides: object.__init__

xappy-0.5/docs/api/xappy.indexerconnection.IndexerConnection-class.html0000644000175000017500000016401511005555243026325 0ustar richardrichard xappy.indexerconnection.IndexerConnection
Package xappy :: Module indexerconnection :: Class IndexerConnection
[frames] | no frames]

Class IndexerConnection

source code

object --+
         |
        IndexerConnection

A connection to the search engine for indexing.

Instance Methods
 
__init__(self, indexpath)
Create a new connection to the index.
source code
 
set_max_mem_use(self, max_mem=None, max_mem_proportion=None)
Set the maximum memory to use.
source code
 
add_field_action(self, fieldname, fieldtype, **kwargs)
Add an action to be performed on a field.
source code
 
clear_field_actions(self, fieldname)
Clear all actions for the specified field.
source code
 
get_fields_with_actions(self)
Get a list of field names which have actions defined.
source code
 
process(self, document)
Process an UnprocessedDocument with the settings in this database.
source code
 
add(self, document)
Add a new document to the search engine index.
source code
 
replace(self, document)
Replace a document in the search engine index.
source code
 
add_synonym(self, original, synonym, field=None, original_field=None, synonym_field=None)
Add a synonym to the index.
source code
 
remove_synonym(self, original, synonym, field=None)
Remove a synonym from the index.
source code
 
clear_synonyms(self, original, field=None)
Remove all synonyms for a word (or phrase).
source code
 
add_subfacet(self, subfacet, facet)
Add a subfacet-facet relationship to the facet hierarchy.
source code
 
remove_subfacet(self, subfacet)
Remove any existing facet hierarchy relationship for a subfacet.
source code
 
get_subfacets(self, facet)
Get a list of subfacets of a facet.
source code
 
set_facet_for_query_type(self, query_type, facet, association)
Set the association between a query type and a facet.
source code
 
get_facets_for_query_type(self, query_type, association)
Get the set of facets associated with a query type.
source code
 
set_metadata(self, key, value)
Set an item of metadata stored in the connection.
source code
 
get_metadata(self, key)
Get an item of metadata stored in the connection.
source code
 
delete(self, id)
Delete a document from the search engine index.
source code
 
flush(self)
Apply recent changes to the database.
source code
 
close(self)
Close the connection to the database.
source code
 
get_doccount(self)
Count the number of documents in the database.
source code
 
iterids(self)
Get an iterator which returns all the ids in the database.
source code
 
get_document(self, id)
Get the document with the specified unique ID.
source code
 
iter_synonyms(self, prefix='')
Get an iterator over the synonyms.
source code
 
iter_subfacets(self)
Get an iterator over the facet hierarchy.
source code
 
iter_facet_query_types(self, association)
Get an iterator over query types and their associated facets.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Class Variables
  FacetQueryType_Preferred = 1
  FacetQueryType_Never = 2
Properties

Inherited from object: __class__

Method Details

__init__(self, indexpath)
(Constructor)

source code 

Create a new connection to the index.

There may only be one indexer connection for a particular database open at a given time. Therefore, if a connection to the database is already open, this will raise a xapian.DatabaseLockError.

If the database doesn't already exist, it will be created.

Overrides: object.__init__

set_max_mem_use(self, max_mem=None, max_mem_proportion=None)

source code 

Set the maximum memory to use.

This call allows the amount of memory to use to buffer changes to be set. This will affect the speed of indexing, but should not result in other changes to the indexing.

Note: this is an approximate measure - the actual amount of memory used max exceed the specified amount. Also, note that future versions of xapian are likely to implement this differently, so this setting may be entirely ignored.

The absolute amount of memory to use (in bytes) may be set by setting max_mem. Alternatively, the proportion of the available memory may be set by setting max_mem_proportion (this should be a value between 0 and 1).

Setting too low a value will result in excessive flushing, and very slow indexing. Setting too high a value will result in excessive buffering, leading to swapping, and very slow indexing.

A reasonable default for max_mem_proportion for a system which is dedicated to indexing is probably 0.5: if other tasks are also being performed on the system, the value should be lowered.

add_field_action(self, fieldname, fieldtype, **kwargs)

source code 

Add an action to be performed on a field.

Note that this change to the configuration will not be preserved on disk until the next call to flush().

clear_field_actions(self, fieldname)

source code 

Clear all actions for the specified field.

This does not report an error if there are already no actions for the specified field.

Note that this change to the configuration will not be preserved on disk until the next call to flush().

process(self, document)

source code 

Process an UnprocessedDocument with the settings in this database.

The resulting ProcessedDocument is returned.

Note that this processing will be automatically performed if an UnprocessedDocument is supplied to the add() or replace() methods of IndexerConnection. This method is exposed to allow the processing to be performed separately, which may be desirable if you wish to manually modify the processed document before adding it to the database, or if you want to split processing of documents from adding documents to the database for performance reasons.

add(self, document)

source code 

Add a new document to the search engine index.

If the document has a id set, and the id already exists in the database, an exception will be raised. Use the replace() method instead if you wish to overwrite documents.

Returns the id of the newly added document (making up a new unique ID if no id was set).

The supplied document may be an instance of UnprocessedDocument, or an instance of ProcessedDocument.

replace(self, document)

source code 

Replace a document in the search engine index.

If the document does not have a id set, an exception will be raised.

If the document has a id set, and the id does not already exist in the database, this method will have the same effect as add().

add_synonym(self, original, synonym, field=None, original_field=None, synonym_field=None)

source code 

Add a synonym to the index.

  • original is the word or words which will be synonym expanded in searches (if multiple words are specified, each word should be separated by a single space).
  • synonym is a synonym for original.
  • field is the field which the synonym is specific to. If no field is specified, the synonym will be used for searches which are not specific to any particular field.

remove_synonym(self, original, synonym, field=None)

source code 

Remove a synonym from the index.

  • original is the word or words which will be synonym expanded in searches (if multiple words are specified, each word should be separated by a single space).
  • synonym is a synonym for original.
  • field is the field which this synonym is specific to. If no field is specified, the synonym will be used for searches which are not specific to any particular field.

clear_synonyms(self, original, field=None)

source code 

Remove all synonyms for a word (or phrase).

  • field is the field which this synonym is specific to. If no field is specified, the synonym will be used for searches which are not specific to any particular field.

add_subfacet(self, subfacet, facet)

source code 

Add a subfacet-facet relationship to the facet hierarchy.

Any existing relationship for that subfacet is replaced.

Raises a KeyError if either facet or subfacet is not a field, and an IndexerError if either facet or subfacet is not a facet field.

set_facet_for_query_type(self, query_type, facet, association)

source code 

Set the association between a query type and a facet.

The value of association must be one of IndexerConnection.FacetQueryType_Preferred, IndexerConnection.FacetQueryType_Never or None. A value of None removes any previously set association.

get_facets_for_query_type(self, query_type, association)

source code 

Get the set of facets associated with a query type.

Only those facets associated with the query type in the specified manner are returned; association must be one of IndexerConnection.FacetQueryType_Preferred or IndexerConnection.FacetQueryType_Never.

If the query type has no facets associated with it, None is returned.

set_metadata(self, key, value)

source code 

Set an item of metadata stored in the connection.

The value supplied will be returned by subsequent calls to get_metadata() which use the same key.

Keys with a leading underscore are reserved for internal use - you should not use such keys unless you really know what you are doing.

This will store the value supplied in the database. It will not be visible to readers (ie, search connections) until after the next flush.

The key is limited to about 200 characters (the same length as a term is limited to). The value can be several megabytes in size.

To remove an item of metadata, simply call this with a value parameter containing an empty string.

get_metadata(self, key)

source code 

Get an item of metadata stored in the connection.

This returns a value stored by a previous call to set_metadata.

If the value is not found, this will return the empty string.

delete(self, id)

source code 

Delete a document from the search engine index.

If the id does not already exist in the database, this method will have no effect (and will not report an error).

flush(self)

source code 

Apply recent changes to the database.

If an exception occurs, any changes since the last call to flush() may be lost.

close(self)

source code 

Close the connection to the database.

It is important to call this method before allowing the class to be garbage collected, because it will ensure that any un-flushed changes will be flushed. It also ensures that the connection is cleaned up promptly.

No other methods may be called on the connection after this has been called. (It is permissible to call close() multiple times, but only the first call will have any effect.)

If an exception occurs, the database will be closed, but changes since the last call to flush may be lost.

get_doccount(self)

source code 

Count the number of documents in the database.

This count will include documents which have been added or removed but not yet flushed().

iterids(self)

source code 

Get an iterator which returns all the ids in the database.

The unqiue_ids are currently returned in binary lexicographical sort order, but this should not be relied on.

get_document(self, id)

source code 

Get the document with the specified unique ID.

Raises a KeyError if there is no such document. Otherwise, it returns a ProcessedDocument.

iter_synonyms(self, prefix='')

source code 

Get an iterator over the synonyms.

  • prefix: if specified, only synonym keys with this prefix will be returned.

The iterator returns 2-tuples, in which the first item is the key (ie, a 2-tuple holding the term or terms which will be synonym expanded, followed by the fieldname specified (or None if no fieldname)), and the second item is a tuple of strings holding the synonyms for the first item.

These return values are suitable for the dict() builtin, so you can write things like:

>>> conn = IndexerConnection('foo')
>>> conn.add_synonym('foo', 'bar')
>>> conn.add_synonym('foo bar', 'baz')
>>> conn.add_synonym('foo bar', 'foo baz')
>>> dict(conn.iter_synonyms())
{('foo', None): ('bar',), ('foo bar', None): ('baz', 'foo baz')}

iter_subfacets(self)

source code 

Get an iterator over the facet hierarchy.

The iterator returns 2-tuples, in which the first item is the subfacet and the second item is its parent facet.

The return values are suitable for the dict() builtin, for example:

>>> conn = IndexerConnection('db')
>>> conn.add_field_action('foo', FieldActions.FACET)
>>> conn.add_field_action('bar', FieldActions.FACET)
>>> conn.add_field_action('baz', FieldActions.FACET)
>>> conn.add_subfacet('foo', 'bar')
>>> conn.add_subfacet('baz', 'bar')
>>> dict(conn.iter_subfacets())
{'foo': 'bar', 'baz': 'bar'}

iter_facet_query_types(self, association)

source code 

Get an iterator over query types and their associated facets.

Only facets associated with the query types in the specified manner are returned; association must be one of IndexerConnection.FacetQueryType_Preferred or IndexerConnection.FacetQueryType_Never.

The iterator returns 2-tuples, in which the first item is the query type and the second item is the associated set of facets.

The return values are suitable for the dict() builtin, for example:

>>> conn = IndexerConnection('db')
>>> conn.add_field_action('foo', FieldActions.FACET)
>>> conn.add_field_action('bar', FieldActions.FACET)
>>> conn.add_field_action('baz', FieldActions.FACET)
>>> conn.set_facet_for_query_type('type1', 'foo', conn.FacetQueryType_Preferred)
>>> conn.set_facet_for_query_type('type1', 'bar', conn.FacetQueryType_Never)
>>> conn.set_facet_for_query_type('type1', 'baz', conn.FacetQueryType_Never)
>>> conn.set_facet_for_query_type('type2', 'bar', conn.FacetQueryType_Preferred)
>>> dict(conn.iter_facet_query_types(conn.FacetQueryType_Preferred))
{'type1': set(['foo']), 'type2': set(['bar'])}
>>> dict(conn.iter_facet_query_types(conn.FacetQueryType_Never))
{'type1': set(['bar', 'baz'])}

xappy-0.5/docs/api/xappy.indexerconnection.PrefixedTermIter-class.html0000644000175000017500000002167511005555243026135 0ustar richardrichard xappy.indexerconnection.PrefixedTermIter
Package xappy :: Module indexerconnection :: Class PrefixedTermIter
[frames] | no frames]

Class PrefixedTermIter

source code

object --+
         |
        PrefixedTermIter

Iterate through all the terms with a given prefix.

Instance Methods
 
__init__(self, prefix, termiter)
Initialise the prefixed term iterator.
source code
 
__iter__(self) source code
 
next(self)
Get the next term with the specified prefix.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, prefix, termiter)
(Constructor)

source code 

Initialise the prefixed term iterator.

  • prefix is the prefix to return terms for.
  • termiter is a xapian TermIterator, which should be at its start.
Overrides: object.__init__

xappy-0.5/docs/api/xappy.indexerconnection.SynonymIter-class.html0000644000175000017500000002203511005555243025202 0ustar richardrichard xappy.indexerconnection.SynonymIter
Package xappy :: Module indexerconnection :: Class SynonymIter
[frames] | no frames]

Class SynonymIter

source code

object --+
         |
        SynonymIter

Iterate through a list of synonyms.

Instance Methods
 
__init__(self, index, field_mappings, prefix)
Initialise the synonym iterator.
source code
 
__iter__(self) source code
 
next(self)
Get the next synonym.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, index, field_mappings, prefix)
(Constructor)

source code 

Initialise the synonym iterator.

  • index is the index to get the synonyms from.
  • field_mappings is the FieldMappings object for the iterator.
  • prefix is the prefix to restrict the returned synonyms to.
Overrides: object.__init__

xappy-0.5/docs/api/xappy.marshall-module.html0000644000175000017500000001304511005555242021150 0ustar richardrichard xappy.marshall
Package xappy :: Module marshall
[frames] | no frames]

Module marshall

source code

marshall.py: Marshal values into strings

Functions
 
float_to_string(value)
Marshall a floating point number to a string which sorts in the appropriate manner.
source code
 
date_to_string(date)
Marshall a date to a string which sorts in the appropriate manner.
source code
xappy-0.5/docs/api/xappy.marshall-pysrc.html0000644000175000017500000002703111005555243021024 0ustar richardrichard xappy.marshall
Package xappy :: Module marshall
[frames] | no frames]

Source Code for Module xappy.marshall

 1  #!/usr/bin/env python 
 2  # 
 3  # Copyright (C) 2007 Lemur Consulting Ltd 
 4  # 
 5  # This program is free software; you can redistribute it and/or modify 
 6  # it under the terms of the GNU General Public License as published by 
 7  # the Free Software Foundation; either version 2 of the License, or 
 8  # (at your option) any later version. 
 9  # 
10  # This program is distributed in the hope that it will be useful, 
11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
13  # GNU General Public License for more details. 
14  #  
15  # You should have received a copy of the GNU General Public License along 
16  # with this program; if not, write to the Free Software Foundation, Inc., 
17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
18  r"""marshall.py: Marshal values into strings 
19   
20  """ 
21  __docformat__ = "restructuredtext en" 
22   
23  import math 
24  import xapian 
25  from replaylog import log as _log 
26   
27 -def float_to_string(value):
28 """Marshall a floating point number to a string which sorts in the 29 appropriate manner. 30 31 """ 32 return _log(xapian.sortable_serialise, value)
33
34 -def date_to_string(date):
35 """Marshall a date to a string which sorts in the appropriate manner. 36 37 """ 38 return '%04d%02d%02d' % (date.year, date.month, date.day)
39

xappy-0.5/docs/api/xappy.memutils-module.html0000644000175000017500000001355111005555242021206 0ustar richardrichard xappy.memutils
Package xappy :: Module memutils
[frames] | no frames]

Module memutils

source code

memutils.py: Memory handling utilities.

Functions
 
get_physical_memory()
Get the amount of physical memory in the system, in bytes.
source code
Function Details

get_physical_memory()

source code 

Get the amount of physical memory in the system, in bytes.

If this can't be obtained, returns None.


xappy-0.5/docs/api/xappy.memutils-pysrc.html0000644000175000017500000005144311005555243021064 0ustar richardrichard xappy.memutils
Package xappy :: Module memutils
[frames] | no frames]

Source Code for Module xappy.memutils

 1  #!/usr/bin/env python 
 2  # 
 3  # Copyright (C) 2007 Lemur Consulting Ltd 
 4  # 
 5  # This program is free software; you can redistribute it and/or modify 
 6  # it under the terms of the GNU General Public License as published by 
 7  # the Free Software Foundation; either version 2 of the License, or 
 8  # (at your option) any later version. 
 9  # 
10  # This program is distributed in the hope that it will be useful, 
11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
13  # GNU General Public License for more details. 
14  #  
15  # You should have received a copy of the GNU General Public License along 
16  # with this program; if not, write to the Free Software Foundation, Inc., 
17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
18  r"""memutils.py: Memory handling utilities. 
19   
20  """ 
21  __docformat__ = "restructuredtext en" 
22   
23  import os 
24   
26 """Try getting a value for the physical memory using os.sysconf(). 27 28 Returns None if no value can be obtained - otherwise, returns a value in 29 bytes. 30 31 """ 32 if getattr(os, 'sysconf', None) is None: 33 return None 34 35 try: 36 pagesize = os.sysconf('SC_PAGESIZE') 37 except ValueError: 38 try: 39 pagesize = os.sysconf('SC_PAGE_SIZE') 40 except ValueError: 41 return None 42 43 try: 44 pagecount = os.sysconf('SC_PHYS_PAGES') 45 except ValueError: 46 return None 47 48 return pagesize * pagecount
49
51 """Try getting a value for the physical memory using GlobalMemoryStatus. 52 53 This is a windows specific method. Returns None if no value can be 54 obtained (eg, not running on windows) - otherwise, returns a value in 55 bytes. 56 57 """ 58 try: 59 import ctypes 60 import ctypes.wintypes as wintypes 61 except ValueError: 62 return None 63 64 class MEMORYSTATUS(wintypes.Structure): 65 _fields_ = [ 66 ('dwLength', wintypes.DWORD), 67 ('dwMemoryLoad', wintypes.DWORD), 68 ('dwTotalPhys', wintypes.DWORD), 69 ('dwAvailPhys', wintypes.DWORD), 70 ('dwTotalPageFile', wintypes.DWORD), 71 ('dwAvailPageFile', wintypes.DWORD), 72 ('dwTotalVirtual', wintypes.DWORD), 73 ('dwAvailVirtual', wintypes.DWORD), 74 ]
75 76 m = MEMORYSTATUS() 77 wintypes.windll.kernel32.GlobalMemoryStatus(wintypes.byref(m)) 78 return m.dwTotalPhys 79
81 """Get the amount of physical memory in the system, in bytes. 82 83 If this can't be obtained, returns None. 84 85 """ 86 result = _get_physical_mem_sysconf() 87 if result is not None: 88 return result 89 return _get_physical_mem_win32()
90

xappy-0.5/docs/api/xappy.parsedate-module.html0000644000175000017500000002617011005555242021320 0ustar richardrichard xappy.parsedate
Package xappy :: Module parsedate
[frames] | no frames]

Module parsedate

source code

parsedate.py: Parse date strings.

Functions
 
date_from_string(value)
Parse a string into a date.
source code
Variables
  yyyymmdd_re = re.compile(r'(?P<year>[0-9]{4})(?P<month>[0-9]{2...
  yyyy_mm_dd_re = re.compile(r'(?P<year>[0-9]{4})([-/\.])(?P<mon...
Function Details

date_from_string(value)

source code 

Parse a string into a date.

If the value supplied is already a date-like object (ie, has 'year', 'month' and 'day' attributes), it is returned without processing.

Supported date formats are:

  • YYYYMMDD
  • YYYY-MM-DD
  • YYYY/MM/DD
  • YYYY.MM.DD

Variables Details

yyyymmdd_re

Value:
re.compile(r'(?P<year>[0-9]{4})(?P<month>[0-9]{2})(?P<day>[0-9]{2})$')

yyyy_mm_dd_re

Value:
re.compile(r'(?P<year>[0-9]{4})([-/\.])(?P<month>[0-9]{2})\2(?P<day>[0\
-9]{2})$')

xappy-0.5/docs/api/xappy.parsedate-pysrc.html0000644000175000017500000004004411005555243021170 0ustar richardrichard xappy.parsedate
Package xappy :: Module parsedate
[frames] | no frames]

Source Code for Module xappy.parsedate

 1  #!/usr/bin/env python 
 2  # 
 3  # Copyright (C) 2007 Lemur Consulting Ltd 
 4  # 
 5  # This program is free software; you can redistribute it and/or modify 
 6  # it under the terms of the GNU General Public License as published by 
 7  # the Free Software Foundation; either version 2 of the License, or 
 8  # (at your option) any later version. 
 9  # 
10  # This program is distributed in the hope that it will be useful, 
11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
13  # GNU General Public License for more details. 
14  #  
15  # You should have received a copy of the GNU General Public License along 
16  # with this program; if not, write to the Free Software Foundation, Inc., 
17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
18  r"""parsedate.py: Parse date strings. 
19   
20  """ 
21  __docformat__ = "restructuredtext en" 
22   
23  import datetime 
24  import re 
25   
26  yyyymmdd_re = re.compile(r'(?P<year>[0-9]{4})(?P<month>[0-9]{2})(?P<day>[0-9]{2})$') 
27  yyyy_mm_dd_re = re.compile(r'(?P<year>[0-9]{4})([-/.])(?P<month>[0-9]{2})\2(?P<day>[0-9]{2})$') 
28   
29 -def date_from_string(value):
30 """Parse a string into a date. 31 32 If the value supplied is already a date-like object (ie, has 'year', 33 'month' and 'day' attributes), it is returned without processing. 34 35 Supported date formats are: 36 37 - YYYYMMDD 38 - YYYY-MM-DD 39 - YYYY/MM/DD 40 - YYYY.MM.DD 41 42 """ 43 if (hasattr(value, 'year') 44 and hasattr(value, 'month') 45 and hasattr(value, 'day')): 46 return value 47 48 mg = yyyymmdd_re.match(value) 49 if mg is None: 50 mg = yyyy_mm_dd_re.match(value) 51 52 if mg is not None: 53 year, month, day = (int(i) for i in mg.group('year', 'month', 'day')) 54 return datetime.date(year, month, day) 55 56 raise ValueError('Unrecognised date format')
57

xappy-0.5/docs/api/xappy.replaylog-module.html0000644000175000017500000001627511005555242021353 0ustar richardrichard xappy.replaylog
Package xappy :: Module replaylog
[frames] | no frames]

Module replaylog

source code

replaylog.py: Log all xapian calls to a file, so that they can be replayed.

Classes
  NotifyingDeleteObject
An wrapping for an object which calls a callback when its deleted.
  ReplayLog
Log of xapian calls, to be replayed.
  LoggedProxy
A proxy for a xapian object, which logs all calls made on the object.
  LoggedProxyMethod
A proxy for a xapian method, which logs all calls made on the method.
Functions
 
set_replay_path(logpath)
Set the path for the replay log.
source code
 
log(call, *args)
Make a call to xapian, and log it.
source code
xappy-0.5/docs/api/xappy.replaylog-pysrc.html0000644000175000017500000033621311005555243021224 0ustar richardrichard xappy.replaylog
Package xappy :: Module replaylog
[frames] | no frames]

Source Code for Module xappy.replaylog

  1  #!/usr/bin/env python 
  2  # 
  3  # Copyright (C) 2007 Lemur Consulting Ltd 
  4  # 
  5  # This program is free software; you can redistribute it and/or modify 
  6  # it under the terms of the GNU General Public License as published by 
  7  # the Free Software Foundation; either version 2 of the License, or 
  8  # (at your option) any later version. 
  9  # 
 10  # This program is distributed in the hope that it will be useful, 
 11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  # GNU General Public License for more details. 
 14  #  
 15  # You should have received a copy of the GNU General Public License along 
 16  # with this program; if not, write to the Free Software Foundation, Inc., 
 17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 18  r"""replaylog.py: Log all xapian calls to a file, so that they can be replayed. 
 19   
 20  """ 
 21  __docformat__ = "restructuredtext en" 
 22   
 23  import datetime 
 24  import sys 
 25  import thread 
 26  import threading 
 27  import time 
 28  import traceback 
 29  import types 
 30  import weakref 
 31  import xapian 
 32   
 33  from pprint import pprint 
 34   
 35  # The logger in use. 
 36  _replay_log = None 
 37   
 38  # True if a replay log has ever been in use since import time. 
 39  _had_replay_log = False 
 40   
41 -class NotifyingDeleteObject(object):
42 """An wrapping for an object which calls a callback when its deleted. 43 44 Note that the callback will be called from a __del__ method, so shouldn't 45 raise any exceptions, and probably shouldn't make new references to the 46 object supplied to it. 47 48 """
49 - def __init__(self, obj, callback):
50 self.obj = obj 51 self.callback = callback
52
53 - def __del__(self):
54 self.callback(self.obj)
55
56 -class ReplayLog(object):
57 """Log of xapian calls, to be replayed. 58 59 """ 60
61 - def __init__(self, logpath):
62 """Create a new replay log. 63 64 """ 65 # Mutex used to protect all access to _fd 66 self._fd_mutex = threading.Lock() 67 self._fd = file(logpath, 'wb') 68 69 # Mutex used to protect all access to members other than _fd 70 self._mutex = threading.Lock() 71 self._next_call = 1 72 73 self._next_thread = 0 74 self._thread_ids = {} 75 76 self._objs = weakref.WeakKeyDictionary() 77 self._next_num = 1 78 79 self._xapian_classes = {} 80 self._xapian_functions = {} 81 self._xapian_methods = {} 82 for name in dir(xapian): 83 item = getattr(xapian, name) 84 has_members = False 85 for membername in dir(item): 86 member = getattr(item, membername) 87 if isinstance(member, types.MethodType): 88 self._xapian_methods[member.im_func] = (name, membername) 89 has_members = True 90 if has_members: 91 self._xapian_classes[item] = name 92 if isinstance(item, types.BuiltinFunctionType): 93 self._xapian_functions[item] = name
94
95 - def _get_obj_num(self, obj, maybe_new):
96 """Get the number associated with an object. 97 98 If maybe_new is False, a value of 0 will be supplied if the object 99 hasn't already been seen. Otherwise, a new (and previously unused) 100 value will be allocated to the object. 101 102 The mutex should be held when this is called. 103 104 """ 105 try: 106 num = self._objs[obj] 107 return num.obj 108 except KeyError: 109 pass 110 111 if not maybe_new: 112 return 0 113 114 self._objs[obj] = NotifyingDeleteObject(self._next_num, self._obj_gone) 115 self._next_num += 1 116 return self._next_num - 1
117
118 - def _is_xap_obj(self, obj):
119 """Return True iff an object is an instance of a xapian object. 120 121 (Also returns true if the object is an instance of a subclass of a 122 xapian object.) 123 124 The mutex should be held when this is called. 125 126 """ 127 # Check for xapian classes. 128 classname = self._xapian_classes.get(type(obj), None) 129 if classname is not None: 130 return True 131 # Check for subclasses of xapian classes. 132 for classobj, classname in self._xapian_classes.iteritems(): 133 if isinstance(obj, classobj): 134 return True 135 # Not a xapian class or subclass. 136 return False
137
138 - def _get_xap_name(self, obj, maybe_new=False):
139 """Get the name of a xapian class or method. 140 141 The mutex should be held when this is called. 142 143 """ 144 # Check if it's a xapian class, or subclass. 145 if isinstance(obj, types.TypeType): 146 classname = self._xapian_classes.get(obj, None) 147 if classname is not None: 148 return classname 149 150 for classobj, classname in self._xapian_classes.iteritems(): 151 if issubclass(obj, classobj): 152 return "subclassof_%s" % (classname, ) 153 154 return None 155 156 # Check if it's a xapian function. 157 if isinstance(obj, types.BuiltinFunctionType): 158 funcname = self._xapian_functions.get(obj, None) 159 if funcname is not None: 160 return funcname 161 162 # Check if it's a proxied object. 163 if isinstance(obj, LoggedProxy): 164 classname = self._xapian_classes.get(obj.__class__, None) 165 if classname is not None: 166 objnum = self._get_obj_num(obj, maybe_new=maybe_new) 167 return "%s#%d" % (classname, objnum) 168 169 # Check if it's a proxied method. 170 if isinstance(obj, LoggedProxyMethod): 171 classname, methodname = self._xapian_methods[obj.real.im_func] 172 objnum = self._get_obj_num(obj.proxyobj, maybe_new=maybe_new) 173 return "%s#%d.%s" % (classname, objnum, methodname) 174 175 # Check if it's a subclass of a xapian class. Note: this will only 176 # pick up subclasses, because the original classes are filtered out 177 # higher up. 178 for classobj, classname in self._xapian_classes.iteritems(): 179 if isinstance(obj, classobj): 180 objnum = self._get_obj_num(obj, maybe_new=maybe_new) 181 return "subclassof_%s#%d" % (classname, objnum) 182 183 return None
184
185 - def _log(self, msg):
186 self._fd_mutex.acquire() 187 try: 188 # msg = '%s,%s' % ( 189 # datetime.datetime.fromtimestamp(time.time()).isoformat(), 190 # msg, 191 # ) 192 self._fd.write(msg) 193 self._fd.flush() 194 finally: 195 self._fd_mutex.release()
196
197 - def _repr_arg(self, arg):
198 """Return a representation of an argument. 199 200 The mutex should be held when this is called. 201 202 """ 203 204 xapargname = self._get_xap_name(arg) 205 if xapargname is not None: 206 return xapargname 207 208 if isinstance(arg, basestring): 209 if isinstance(arg, unicode): 210 arg = arg.encode('utf-8') 211 return 'str(%d,%s)' % (len(arg), arg) 212 213 if isinstance(arg, long): 214 try: 215 arg = int(arg) 216 except OverFlowError: 217 pass 218 219 if isinstance(arg, long): 220 return 'long(%d)' % arg 221 222 if isinstance(arg, int): 223 return 'int(%d)' % arg 224 225 if isinstance(arg, float): 226 return 'float(%f)' % arg 227 228 if arg is None: 229 return 'None' 230 231 if hasattr(arg, '__iter__'): 232 seq = [] 233 for item in arg: 234 seq.append(self._repr_arg(item)) 235 return 'list(%s)' % ','.join(seq) 236 237 return 'UNKNOWN:' + str(arg)
238
239 - def _repr_args(self, args):
240 """Return a representation of a list of arguments. 241 242 The mutex should be held when this is called. 243 244 """ 245 logargs = [] 246 for arg in args: 247 logargs.append(self._repr_arg(arg)) 248 return ','.join(logargs)
249
250 - def _get_call_id(self):
251 """Get an ID string for a call. 252 253 The mutex should be held when this is called. 254 255 """ 256 call_num = self._next_call 257 self._next_call += 1 258 259 thread_id = thread.get_ident() 260 try: 261 thread_num = self._thread_ids[thread_id] 262 except KeyError: 263 thread_num = self._next_thread 264 self._thread_ids[thread_id] = thread_num 265 self._next_thread += 1 266 267 if thread_num is 0: 268 return "%s" % call_num 269 return "%dT%d" % (call_num, thread_num)
270
271 - def log_call(self, call, *args):
272 """Add a log message about a call. 273 274 Returns a number for the call, so it can be tied to a particular 275 result. 276 277 """ 278 self._mutex.acquire() 279 try: 280 logargs = self._repr_args(args) 281 xapobjname = self._get_xap_name(call) 282 call_id = self._get_call_id() 283 finally: 284 self._mutex.release() 285 286 if xapobjname is not None: 287 self._log("CALL%s:%s(%s)\n" % (call_id, xapobjname, logargs)) 288 else: 289 self._log("CALL%s:UNKNOWN:%r(%s)\n" % (call_id, call, logargs)) 290 return call_id
291
292 - def log_except(self, (etype, value, tb), call_id):
293 """Log an exception which has occurred. 294 295 """ 296 # No access to an members, so no need to acquire mutex. 297 exc = traceback.format_exception_only(etype, value) 298 self._log("EXCEPT%s:%s\n" % (call_id, ''.join(exc).strip()))
299
300 - def log_retval(self, ret, call_id):
301 """Log a return value. 302 303 """ 304 if ret is None: 305 self._log("RET%s:None\n" % call_id) 306 return 307 308 self._mutex.acquire() 309 try: 310 # If it's a xapian object, return a proxy for it. 311 if self._is_xap_obj(ret): 312 ret = LoggedProxy(ret) 313 xapobjname = self._get_xap_name(ret, maybe_new=True) 314 msg = "RET%s:%s\n" % (call_id, self._repr_arg(ret)) 315 finally: 316 self._mutex.release() 317 318 # Not a xapian object - just return it. 319 self._log(msg) 320 return ret
321
322 - def _obj_gone(self, num):
323 """Log that an object has been deleted. 324 325 """ 326 self._log('DEL:#%d\n' % num)
327
328 -class LoggedProxy(object):
329 """A proxy for a xapian object, which logs all calls made on the object. 330 331 """
332 - def __init__(self, obj):
333 self.__obj = obj
334
335 - def __getattribute__(self, name):
336 obj = object.__getattribute__(self, '_LoggedProxy__obj') 337 if name == '__obj': 338 return obj 339 real = getattr(obj, name) 340 if not isinstance(real, types.MethodType): 341 return real 342 return LoggedProxyMethod(real, self)
343
344 - def __iter__(self):
345 obj = object.__getattribute__(self, '_LoggedProxy__obj') 346 return obj.__iter__()
347
348 - def __len__(self):
349 obj = object.__getattribute__(self, '_LoggedProxy__obj') 350 return obj.__len__()
351
352 - def __repr__(self):
353 obj = object.__getattribute__(self, '_LoggedProxy__obj') 354 return '<LoggedProxy of %s >' % obj.__repr__()
355
356 - def __str__(self):
357 obj = object.__getattribute__(self, '_LoggedProxy__obj') 358 return obj.__str__()
359
360 -class LoggedProxyMethod(object):
361 """A proxy for a xapian method, which logs all calls made on the method. 362 363 """
364 - def __init__(self, real, proxyobj):
365 """Make a proxy for the method. 366 367 """ 368 self.real = real 369 self.proxyobj = proxyobj
370
371 - def __call__(self, *args):
372 """Call the proxied method, logging the call. 373 374 """ 375 return log(self, *args)
376
377 -def set_replay_path(logpath):
378 """Set the path for the replay log. 379 380 """ 381 global _replay_log 382 global _had_replay_log 383 if logpath is None: 384 _replay_log = None 385 else: 386 _had_replay_log = True 387 _replay_log = ReplayLog(logpath)
388
389 -def _unproxy_call_and_args(call, args):
390 """Convert a call and list of arguments to unproxied form. 391 392 """ 393 if isinstance(call, LoggedProxyMethod): 394 realcall = call.real 395 else: 396 realcall = call 397 398 realargs = [] 399 for arg in args: 400 if isinstance(arg, LoggedProxy): 401 arg = arg.__obj 402 realargs.append(arg) 403 404 return realcall, realargs
405
406 -def log(call, *args):
407 """Make a call to xapian, and log it. 408 409 """ 410 # If we've never had a replay log in force, no need to unproxy objects. 411 global _had_replay_log 412 if not _had_replay_log: 413 return call(*args) 414 415 # Get unproxied versions of the call and arguments. 416 realcall, realargs = _unproxy_call_and_args(call, args) 417 418 # If we have no replay log currently, just do the call. 419 global _replay_log 420 replay_log = _replay_log 421 if replay_log is None: 422 return realcall(*realargs) 423 424 # We have a replay log: do a logged version of the call. 425 call_id = replay_log.log_call(call, *args) 426 try: 427 ret = realcall(*realargs) 428 except: 429 replay_log.log_except(sys.exc_info(), call_id) 430 raise 431 return replay_log.log_retval(ret, call_id)
432 433 #set_replay_path('replay.log') 434

xappy-0.5/docs/api/xappy.replaylog.LoggedProxy-class.html0000644000175000017500000003173411005555243023433 0ustar richardrichard xappy.replaylog.LoggedProxy
Package xappy :: Module replaylog :: Class LoggedProxy
[frames] | no frames]

Class LoggedProxy

source code

object --+
         |
        LoggedProxy

A proxy for a xapian object, which logs all calls made on the object.

Instance Methods
 
__init__(self, obj)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
__getattribute__(self, name)
x.__getattribute__('name') <==> x.name
source code
 
__iter__(self) source code
 
__len__(self) source code
 
__repr__(self)
repr(x)
source code
 
__str__(self)
str(x)
source code

Inherited from object: __delattr__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__

Properties

Inherited from object: __class__

Method Details

__init__(self, obj)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

__getattribute__(self, name)

source code 
x.__getattribute__('name') <==> x.name
Overrides: object.__getattribute__
(inherited documentation)

__repr__(self)
(Representation operator)

source code 
repr(x)
Overrides: object.__repr__
(inherited documentation)

__str__(self)
(Informal representation operator)

source code 
str(x)
Overrides: object.__str__
(inherited documentation)

xappy-0.5/docs/api/xappy.replaylog.LoggedProxyMethod-class.html0000644000175000017500000002012511005555243024564 0ustar richardrichard xappy.replaylog.LoggedProxyMethod
Package xappy :: Module replaylog :: Class LoggedProxyMethod
[frames] | no frames]

Class LoggedProxyMethod

source code

object --+
         |
        LoggedProxyMethod

A proxy for a xapian method, which logs all calls made on the method.

Instance Methods
 
__init__(self, real, proxyobj)
Make a proxy for the method.
source code
 
__call__(self, *args)
Call the proxied method, logging the call.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, real, proxyobj)
(Constructor)

source code 
Make a proxy for the method.
Overrides: object.__init__

xappy-0.5/docs/api/xappy.replaylog.NotifyingDeleteObject-class.html0000644000175000017500000002053411005555243025404 0ustar richardrichard xappy.replaylog.NotifyingDeleteObject
Package xappy :: Module replaylog :: Class NotifyingDeleteObject
[frames] | no frames]

Class NotifyingDeleteObject

source code

object --+
         |
        NotifyingDeleteObject

An wrapping for an object which calls a callback when its deleted.

Note that the callback will be called from a __del__ method, so shouldn't raise any exceptions, and probably shouldn't make new references to the object supplied to it.



Instance Methods
 
__init__(self, obj, callback)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
__del__(self) source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, obj, callback)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

xappy-0.5/docs/api/xappy.replaylog.ReplayLog-class.html0000644000175000017500000002443011005555243023061 0ustar richardrichard xappy.replaylog.ReplayLog
Package xappy :: Module replaylog :: Class ReplayLog
[frames] | no frames]

Class ReplayLog

source code

object --+
         |
        ReplayLog

Log of xapian calls, to be replayed.

Instance Methods
 
__init__(self, logpath)
Create a new replay log.
source code
 
log_call(self, call, *args)
Add a log message about a call.
source code
 
log_except(self, (etype, value, tb), call_id)
Log an exception which has occurred.
source code
 
log_retval(self, ret, call_id)
Log a return value.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, logpath)
(Constructor)

source code 
Create a new replay log.
Overrides: object.__init__

log_call(self, call, *args)

source code 

Add a log message about a call.

Returns a number for the call, so it can be tied to a particular result.


xappy-0.5/docs/api/xappy.schema-module.html0000644000175000017500000001054211005555242020604 0ustar richardrichard xappy.schema
Package xappy :: Module schema
[frames] | no frames]

Module schema

source code

schema.py: xdefinitions and implementations of field actions.

Classes
  Schema
xappy-0.5/docs/api/xappy.schema-pysrc.html0000644000175000017500000002561411005555243020466 0ustar richardrichard xappy.schema
Package xappy :: Module schema
[frames] | no frames]

Source Code for Module xappy.schema

 1  #!/usr/bin/env python 
 2  # 
 3  # Copyright (C) 2008 Lemur Consulting Ltd 
 4  # 
 5  # This program is free software; you can redistribute it and/or modify 
 6  # it under the terms of the GNU General Public License as published by 
 7  # the Free Software Foundation; either version 2 of the License, or 
 8  # (at your option) any later version. 
 9  # 
10  # This program is distributed in the hope that it will be useful, 
11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
13  # GNU General Public License for more details. 
14  #  
15  # You should have received a copy of the GNU General Public License along 
16  # with this program; if not, write to the Free Software Foundation, Inc., 
17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
18  r"""schema.py: xdefinitions and implementations of field actions. 
19   
20  """ 
21  __docformat__ = "restructuredtext en" 
22   
23  import errors as _errors 
24  from replaylog import log as _log 
25  import parsedate as _parsedate 
26   
27 -class Schema(object):
28 - def __init__(self):
29 pass
30 31 if __name__ == '__main__': 32 import doctest, sys 33 doctest.testmod (sys.modules[__name__]) 34

xappy-0.5/docs/api/xappy.schema.Schema-class.html0000644000175000017500000001615511005555243021632 0ustar richardrichard xappy.schema.Schema
Package xappy :: Module schema :: Class Schema
[frames] | no frames]

Class Schema

source code

object --+
         |
        Schema

Instance Methods
 
__init__(self)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

xappy-0.5/docs/api/xappy.searchconnection-module.html0000644000175000017500000001265511005555242022700 0ustar richardrichard xappy.searchconnection
Package xappy :: Module searchconnection
[frames] | no frames]

Module searchconnection

source code

searchconnection.py: A connection to the search engine for searching.

Classes
  SearchResult
A result from a search.
  SearchResultIter
An iterator over a set of results from a search.
  SearchResults
A set of results of a search.
  SearchConnection
A connection to the search engine for searching.
xappy-0.5/docs/api/xappy.searchconnection-pysrc.html0000644000175000017500000175367611005555243022574 0ustar richardrichard xappy.searchconnection
Package xappy :: Module searchconnection
[frames] | no frames]

Source Code for Module xappy.searchconnection

   1  #!/usr/bin/env python 
   2  # 
   3  # Copyright (C) 2007 Lemur Consulting Ltd 
   4  # 
   5  # This program is free software; you can redistribute it and/or modify 
   6  # it under the terms of the GNU General Public License as published by 
   7  # the Free Software Foundation; either version 2 of the License, or 
   8  # (at your option) any later version. 
   9  # 
  10  # This program is distributed in the hope that it will be useful, 
  11  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  13  # GNU General Public License for more details. 
  14  #  
  15  # You should have received a copy of the GNU General Public License along 
  16  # with this program; if not, write to the Free Software Foundation, Inc., 
  17  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
  18  r"""searchconnection.py: A connection to the search engine for searching. 
  19   
  20  """ 
  21  __docformat__ = "restructuredtext en" 
  22   
  23  import _checkxapian 
  24  import os as _os 
  25  import cPickle as _cPickle 
  26  import math 
  27   
  28  import xapian as _xapian 
  29  from datastructures import * 
  30  from fieldactions import * 
  31  import fieldmappings as _fieldmappings 
  32  import highlight as _highlight  
  33  import errors as _errors 
  34  import indexerconnection as _indexerconnection 
  35  import re as _re 
  36  from replaylog import log as _log 
  37   
38 -class SearchResult(ProcessedDocument):
39 """A result from a search. 40 41 As well as being a ProcessedDocument representing the document in the 42 database, the result has several members which may be used to get 43 information about how well the document matches the search: 44 45 - `rank`: The rank of the document in the search results, starting at 0 46 (ie, 0 is the "top" result, 1 is the second result, etc). 47 48 - `weight`: A floating point number indicating the weight of the result 49 document. The value is only meaningful relative to other results for a 50 given search - a different search, or the same search with a different 51 database, may give an entirely different scale to the weights. This 52 should not usually be displayed to users, but may be useful if trying to 53 perform advanced reweighting operations on search results. 54 55 - `percent`: A percentage value for the weight of a document. This is 56 just a rescaled form of the `weight` member. It doesn't represent any 57 kind of probability value; the only real meaning of the numbers is that, 58 within a single set of results, a document with a higher percentage 59 corresponds to a better match. Because the percentage doesn't really 60 represent a probability, or a confidence value, it is probably unhelpful 61 to display it to most users, since they tend to place an over emphasis 62 on its meaning. However, it is included because it may be useful 63 occasionally. 64 65 """
66 - def __init__(self, msetitem, results):
67 ProcessedDocument.__init__(self, results._fieldmappings, msetitem.document) 68 self.rank = msetitem.rank 69 self.weight = msetitem.weight 70 self.percent = msetitem.percent 71 self._results = results
72
73 - def _get_language(self, field):
74 """Get the language that should be used for a given field. 75 76 Raises a KeyError if the field is not known. 77 78 """ 79 actions = self._results._conn._field_actions[field]._actions 80 for action, kwargslist in actions.iteritems(): 81 if action == FieldActions.INDEX_FREETEXT: 82 for kwargs in kwargslist: 83 try: 84 return kwargs['language'] 85 except KeyError: 86 pass 87 return 'none'
88
89 - def summarise(self, field, maxlen=600, hl=('<b>', '</b>'), query=None):
90 """Return a summarised version of the field specified. 91 92 This will return a summary of the contents of the field stored in the 93 search result, with words which match the query highlighted. 94 95 The maximum length of the summary (in characters) may be set using the 96 maxlen parameter. 97 98 The return value will be a string holding the summary, with 99 highlighting applied. If there are multiple instances of the field in 100 the document, the instances will be joined with a newline character. 101 102 To turn off highlighting, set hl to None. Each highlight will consist 103 of the first entry in the `hl` list being placed before the word, and 104 the second entry in the `hl` list being placed after the word. 105 106 Any XML or HTML style markup tags in the field will be stripped before 107 the summarisation algorithm is applied. 108 109 If `query` is supplied, it should contain a Query object, as returned 110 from SearchConnection.query_parse() or related methods, which will be 111 used as the basis of the summarisation and highlighting rather than the 112 query which was used for the search. 113 114 Raises KeyError if the field is not known. 115 116 """ 117 highlighter = _highlight.Highlighter(language_code=self._get_language(field)) 118 field = self.data[field] 119 results = [] 120 text = '\n'.join(field) 121 if query is None: 122 query = self._results._query 123 return highlighter.makeSample(text, query, maxlen, hl)
124
125 - def highlight(self, field, hl=('<b>', '</b>'), strip_tags=False, query=None):
126 """Return a highlighted version of the field specified. 127 128 This will return all the contents of the field stored in the search 129 result, with words which match the query highlighted. 130 131 The return value will be a list of strings (corresponding to the list 132 of strings which is the raw field data). 133 134 Each highlight will consist of the first entry in the `hl` list being 135 placed before the word, and the second entry in the `hl` list being 136 placed after the word. 137 138 If `strip_tags` is True, any XML or HTML style markup tags in the field 139 will be stripped before highlighting is applied. 140 141 If `query` is supplied, it should contain a Query object, as returned 142 from SearchConnection.query_parse() or related methods, which will be 143 used as the basis of the summarisation and highlighting rather than the 144 query which was used for the search. 145 146 Raises KeyError if the field is not known. 147 148 """ 149 highlighter = _highlight.Highlighter(language_code=self._get_language(field)) 150 field = self.data[field] 151 results = [] 152 if query is None: 153 query = self._results._query 154 for text in field: 155 results.append(highlighter.highlight(text, query, hl, strip_tags)) 156 return results
157
158 - def __repr__(self):
159 return ('<SearchResult(rank=%d, id=%r, data=%r)>' % 160 (self.rank, self.id, self.data))
161 162
163 -class SearchResultIter(object):
164 """An iterator over a set of results from a search. 165 166 """
167 - def __init__(self, results, order):
168 self._results = results 169 self._order = order 170 if self._order is None: 171 self._iter = iter(results._mset) 172 else: 173 self._iter = iter(self._order)
174
175 - def next(self):
176 if self._order is None: 177 msetitem = self._iter.next() 178 else: 179 index = self._iter.next() 180 msetitem = self._results._mset.get_hit(index) 181 return SearchResult(msetitem, self._results)
182 183
184 -def _get_significant_digits(value, lower, upper):
185 """Get the significant digits of value which are constrained by the 186 (inclusive) lower and upper bounds. 187 188 If there are no significant digits which are definitely within the 189 bounds, exactly one significant digit will be returned in the result. 190 191 >>> _get_significant_digits(15,15,15) 192 15 193 >>> _get_significant_digits(15,15,17) 194 20 195 >>> _get_significant_digits(4777,208,6000) 196 5000 197 >>> _get_significant_digits(4777,4755,4790) 198 4800 199 >>> _get_significant_digits(4707,4695,4710) 200 4700 201 >>> _get_significant_digits(4719,4717,4727) 202 4720 203 >>> _get_significant_digits(0,0,0) 204 0 205 >>> _get_significant_digits(9,9,10) 206 9 207 >>> _get_significant_digits(9,9,100) 208 9 209 210 """ 211 assert(lower <= value) 212 assert(value <= upper) 213 diff = upper - lower 214 215 # Get the first power of 10 greater than the difference. 216 # This corresponds to the magnitude of the smallest significant digit. 217 if diff == 0: 218 pos_pow_10 = 1 219 else: 220 pos_pow_10 = int(10 ** math.ceil(math.log10(diff))) 221 222 # Special case for situation where we don't have any significant digits: 223 # get the magnitude of the most significant digit in value. 224 if pos_pow_10 > value: 225 if value == 0: 226 pos_pow_10 = 1 227 else: 228 pos_pow_10 = int(10 ** math.floor(math.log10(value))) 229 230 # Return the value, rounded to the nearest multiple of pos_pow_10 231 return ((value + pos_pow_10 // 2) // pos_pow_10) * pos_pow_10
232
233 -class SearchResults(object):
234 """A set of results of a search. 235 236 """
237 - def __init__(self, conn, enq, query, mset, fieldmappings, tagspy, 238 tagfields, facetspy, facetfields, facethierarchy, 239 facetassocs):
240 self._conn = conn 241 self._enq = enq 242 self._query = query 243 self._mset = mset 244 self._mset_order = None 245 self._fieldmappings = fieldmappings 246 self._tagspy = tagspy 247 if tagfields is None: 248 self._tagfields = None 249 else: 250 self._tagfields = set(tagfields) 251 self._facetspy = facetspy 252 self._facetfields = facetfields 253 self._facethierarchy = facethierarchy 254 self._facetassocs = facetassocs 255 self._numeric_ranges_built = {}
256
257 - def _cluster(self, num_clusters, maxdocs, fields=None):
258 """Cluster results based on similarity. 259 260 Note: this method is experimental, and will probably disappear or 261 change in the future. 262 263 The number of clusters is specified by num_clusters: unless there are 264 too few results, there will be exaclty this number of clusters in the 265 result. 266 267 """ 268 clusterer = _xapian.ClusterSingleLink() 269 xapclusters = _xapian.ClusterAssignments() 270 docsim = _xapian.DocSimCosine() 271 source = _xapian.MSetDocumentSource(self._mset, maxdocs) 272 273 if fields is None: 274 clusterer.cluster(self._conn._index, xapclusters, docsim, source, num_clusters) 275 else: 276 decider = self._make_expand_decider(fields) 277 clusterer.cluster(self._conn._index, xapclusters, docsim, source, decider, num_clusters) 278 279 newid = 0 280 idmap = {} 281 clusters = {} 282 for item in self._mset: 283 docid = item.docid 284 clusterid = xapclusters.cluster(docid) 285 if clusterid not in idmap: 286 idmap[clusterid] = newid 287 newid += 1 288 clusterid = idmap[clusterid] 289 if clusterid not in clusters: 290 clusters[clusterid] = [] 291 clusters[clusterid].append(item.rank) 292 return clusters
293
294 - def _reorder_by_clusters(self, clusters):
295 """Reorder the mset based on some clusters. 296 297 """ 298 if self.startrank != 0: 299 raise _errors.SearchError("startrank must be zero to reorder by clusters") 300 reordered = False 301 tophits = [] 302 nottophits = [] 303 304 clusterstarts = dict(((c[0], None) for c in clusters.itervalues())) 305 for i in xrange(self.endrank): 306 if i in clusterstarts: 307 tophits.append(i) 308 else: 309 nottophits.append(i) 310 self._mset_order = tophits 311 self._mset_order.extend(nottophits)
312
313 - def _make_expand_decider(self, fields):
314 """Make an expand decider which accepts only terms in the specified 315 field. 316 317 """ 318 prefixes = {} 319 if isinstance(fields, basestring): 320 fields = [fields] 321 for field in fields: 322 try: 323 actions = self._conn._field_actions[field]._actions 324 except KeyError: 325 continue 326 for action, kwargslist in actions.iteritems(): 327 if action == FieldActions.INDEX_FREETEXT: 328 prefix = self._conn._field_mappings.get_prefix(field) 329 prefixes[prefix] = None 330 prefixes['Z' + prefix] = None 331 if action in (FieldActions.INDEX_EXACT, 332 FieldActions.TAG, 333 FieldActions.FACET,): 334 prefix = self._conn._field_mappings.get_prefix(field) 335 prefixes[prefix] = None 336 prefix_re = _re.compile('|'.join([_re.escape(x) + '[^A-Z]' for x in prefixes.keys()])) 337 class decider(_xapian.ExpandDecider): 338 def __call__(self, term): 339 return prefix_re.match(term) is not None
340 return decider() 341
342 - def _reorder_by_similarity(self, count, maxcount, max_similarity, 343 fields=None):
344 """Reorder results based on similarity. 345 346 The top `count` documents will be chosen such that they are relatively 347 dissimilar. `maxcount` documents will be considered for moving around, 348 and `max_similarity` is a value between 0 and 1 indicating the maximum 349 similarity to the previous document before a document is moved down the 350 result set. 351 352 Note: this method is experimental, and will probably disappear or 353 change in the future. 354 355 """ 356 if self.startrank != 0: 357 raise _errors.SearchError("startrank must be zero to reorder by similiarity") 358 ds = _xapian.DocSimCosine() 359 ds.set_termfreqsource(_xapian.DatabaseTermFreqSource(self._conn._index)) 360 361 if fields is not None: 362 ds.set_expand_decider(self._make_expand_decider(fields)) 363 364 tophits = [] 365 nottophits = [] 366 full = False 367 reordered = False 368 369 sim_count = 0 370 new_order = [] 371 end = min(self.endrank, maxcount) 372 for i in xrange(end): 373 if full: 374 new_order.append(i) 375 continue 376 hit = self._mset.get_hit(i) 377 if len(tophits) == 0: 378 tophits.append(hit) 379 continue 380 381 # Compare each incoming hit to tophits 382 maxsim = 0.0 383 for tophit in tophits[-1:]: 384 sim_count += 1 385 sim = ds.similarity(hit.document, tophit.document) 386 if sim > maxsim: 387 maxsim = sim 388 389 # If it's not similar to an existing hit, add to tophits. 390 if maxsim < max_similarity: 391 tophits.append(hit) 392 else: 393 nottophits.append(hit) 394 reordered = True 395 396 # If we're full of hits, append to the end. 397 if len(tophits) >= count: 398 for hit in tophits: 399 new_order.append(hit.rank) 400 for hit in nottophits: 401 new_order.append(hit.rank) 402 full = True 403 if not full: 404 for hit in tophits: 405 new_order.append(hit.rank) 406 for hit in nottophits: 407 new_order.append(hit.rank) 408 if end != self.endrank: 409 new_order.extend(range(end, self.endrank)) 410 assert len(new_order) == self.endrank 411 if reordered: 412 self._mset_order = new_order 413 else: 414 assert new_order == range(self.endrank)
415
416 - def __repr__(self):
417 return ("<SearchResults(startrank=%d, " 418 "endrank=%d, " 419 "more_matches=%s, " 420 "matches_lower_bound=%d, " 421 "matches_upper_bound=%d, " 422 "matches_estimated=%d, " 423 "estimate_is_exact=%s)>" % 424 ( 425 self.startrank, 426 self.endrank, 427 self.more_matches, 428 self.matches_lower_bound, 429 self.matches_upper_bound, 430 self.matches_estimated, 431 self.estimate_is_exact, 432 ))
433
434 - def _get_more_matches(self):
435 # This check relies on us having asked for at least one more result 436 # than retrieved to be checked. 437 return (self.matches_lower_bound > self.endrank)
438 more_matches = property(_get_more_matches, doc= 439 """Check whether there are further matches after those in this result set. 440 441 """) 442
443 - def _get_startrank(self):
444 return self._mset.get_firstitem()
445 startrank = property(_get_startrank, doc= 446 """Get the rank of the first item in the search results. 447 448 This corresponds to the "startrank" parameter passed to the search() method. 449 450 """) 451
452 - def _get_endrank(self):
453 return self._mset.get_firstitem() + len(self._mset)
454 endrank = property(_get_endrank, doc= 455 """Get the rank of the item after the end of the search results. 456 457 If there are sufficient results in the index, this corresponds to the 458 "endrank" parameter passed to the search() method. 459 460 """) 461
462 - def _get_lower_bound(self):
463 return self._mset.get_matches_lower_bound()
464 matches_lower_bound = property(_get_lower_bound, doc= 465 """Get a lower bound on the total number of matching documents. 466 467 """) 468
469 - def _get_upper_bound(self):
470 return self._mset.get_matches_upper_bound()
471 matches_upper_bound = property(_get_upper_bound, doc= 472 """Get an upper bound on the total number of matching documents. 473 474 """) 475
477 lower = self._mset.get_matches_lower_bound() 478 upper = self._mset.get_matches_upper_bound() 479 est = self._mset.get_matches_estimated() 480 return _get_significant_digits(est, lower, upper)
481 matches_human_readable_estimate = property(_get_human_readable_estimate, 482 doc= 483 """Get a human readable estimate of the number of matching documents. 484 485 This consists of the value returned by the "matches_estimated" property, 486 rounded to an appropriate number of significant digits (as determined by 487 the values of the "matches_lower_bound" and "matches_upper_bound" 488 properties). 489 490 """) 491
492 - def _get_estimated(self):
493 return self._mset.get_matches_estimated()
494 matches_estimated = property(_get_estimated, doc= 495 """Get an estimate for the total number of matching documents. 496 497 """) 498
499 - def _estimate_is_exact(self):
500 return self._mset.get_matches_lower_bound() == \ 501 self._mset.get_matches_upper_bound()
502 estimate_is_exact = property(_estimate_is_exact, doc= 503 """Check whether the estimated number of matching documents is exact. 504 505 If this returns true, the estimate given by the `matches_estimated` 506 property is guaranteed to be correct. 507 508 If this returns false, it is possible that the actual number of matching 509 documents is different from the number given by the `matches_estimated` 510 property. 511 512 """) 513
514 - def get_hit(self, index):
515 """Get the hit with a given index. 516 517 """ 518 if self._mset_order is None: 519 msetitem = self._mset.get_hit(index) 520 else: 521 msetitem = self._mset.get_hit(self._mset_order[index]) 522 return SearchResult(msetitem, self)
523 __getitem__ = get_hit 524
525 - def __iter__(self):
526 """Get an iterator over the hits in the search result. 527 528 The iterator returns the results in increasing order of rank. 529 530 """ 531 return SearchResultIter(self, self._mset_order)
532
533 - def __len__(self):
534 """Get the number of hits in the search result. 535 536 Note that this is not (usually) the number of matching documents for 537 the search. If startrank is non-zero, it's not even the rank of the 538 last document in the search result. It's simply the number of hits 539 stored in the search result. 540 541 It is, however, the number of items returned by the iterator produced 542 by calling iter() on this SearchResults object. 543 544 """ 545 return len(self._mset)
546
547 - def get_top_tags(self, field, maxtags):
548 """Get the most frequent tags in a given field. 549 550 - `field` - the field to get tags for. This must have been specified 551 in the "gettags" argument of the search() call. 552 - `maxtags` - the maximum number of tags to return. 553 554 Returns a sequence of 2-item tuples, in which the first item in the 555 tuple is the tag, and the second is the frequency of the tag in the 556 matches seen (as an integer). 557 558 """ 559 if 'tags' in _checkxapian.missing_features: 560 raise errors.SearchError("Tags unsupported with this release of xapian") 561 if self._tagspy is None or field not in self._tagfields: 562 raise _errors.SearchError("Field %r was not specified for getting tags" % field) 563 prefix = self._conn._field_mappings.get_prefix(field) 564 return self._tagspy.get_top_terms(prefix, maxtags)
565
566 - def get_suggested_facets(self, maxfacets=5, desired_num_of_categories=7, 567 required_facets=None):
568 """Get a suggested set of facets, to present to the user. 569 570 This returns a list, in descending order of the usefulness of the 571 facet, in which each item is a tuple holding: 572 573 - fieldname of facet. 574 - sequence of 2-tuples holding the suggested values or ranges for that 575 field: 576 577 For facets of type 'string', the first item in the 2-tuple will 578 simply be the string supplied when the facet value was added to its 579 document. For facets of type 'float', it will be a 2-tuple, holding 580 floats giving the start and end of the suggested value range. 581 582 The second item in the 2-tuple will be the frequency of the facet 583 value or range in the result set. 584 585 If required_facets is not None, it must be a field name, or a sequence 586 of field names. Any field names mentioned in required_facets will be 587 returned if there are any facet values at all in the search results for 588 that field. The facet will only be omitted if there are no facet 589 values at all for the field. 590 591 The value of maxfacets will be respected as far as possible; the 592 exception is that if there are too many fields listed in 593 required_facets with at least one value in the search results, extra 594 facets will be returned (ie, obeying the required_facets parameter is 595 considered more important than the maxfacets parameter). 596 597 If facet_hierarchy was indicated when search() was called, and the 598 query included facets, then only subfacets of those query facets and 599 top-level facets will be included in the returned list. Furthermore 600 top-level facets will only be returned if there are remaining places 601 in the list after it has been filled with subfacets. Note that 602 required_facets is still respected regardless of the facet hierarchy. 603 604 If a query type was specified when search() was called, and the query 605 included facets, then facets with an association of Never to the 606 query type are never returned, even if mentioned in required_facets. 607 Facets with an association of Preferred are listed before others in 608 the returned list. 609 610 """ 611 if 'facets' in _checkxapian.missing_features: 612 raise errors.SearchError("Facets unsupported with this release of xapian") 613 if self._facetspy is None: 614 raise _errors.SearchError("Facet selection wasn't enabled when the search was run") 615 if isinstance(required_facets, basestring): 616 required_facets = [required_facets] 617 scores = [] 618 facettypes = {} 619 for field, slot, kwargslist in self._facetfields: 620 type = None 621 for kwargs in kwargslist: 622 type = kwargs.get('type', None) 623 if type is not None: break 624 if type is None: type = 'string' 625 626 if type == 'float': 627 if field not in self._numeric_ranges_built: 628 self._facetspy.build_numeric_ranges(slot, desired_num_of_categories) 629 self._numeric_ranges_built[field] = None 630 facettypes[field] = type 631 score = self._facetspy.score_categorisation(slot, desired_num_of_categories) 632 scores.append((score, field, slot)) 633 634 # Sort on whether facet is top-level ahead of score (use subfacets first), 635 # and on whether facet is preferred for the query type ahead of anything else 636 if self._facethierarchy: 637 # Note, tuple[-2] is the value of 'field' in a scores tuple 638 scores = [(tuple[-2] not in self._facethierarchy,) + tuple for tuple in scores] 639 if self._facetassocs: 640 preferred = _indexerconnection.IndexerConnection.FacetQueryType_Preferred 641 scores = [(self._facetassocs.get(tuple[-2]) != preferred,) + tuple for tuple in scores] 642 scores.sort() 643 if self._facethierarchy: 644 index = 1 645 else: 646 index = 0 647 if self._facetassocs: 648 index += 1 649 if index > 0: 650 scores = [tuple[index:] for tuple in scores] 651 652 results = [] 653 required_results = [] 654 for score, field, slot in scores: 655 # Check if the facet is required 656 required = False 657 if required_facets is not None: 658 required = field in required_facets 659 660 # If we've got enough facets, and the field isn't required, skip it 661 if not required and len(results) + len(required_results) >= maxfacets: 662 continue 663 664 # Get the values 665 values = self._facetspy.get_values_as_dict(slot) 666 if field in self._numeric_ranges_built: 667 if '' in values: 668 del values[''] 669 670 # Required facets must occur at least once, other facets must occur 671 # at least twice. 672 if required: 673 if len(values) < 1: 674 continue 675 else: 676 if len(values) <= 1: 677 continue 678 679 newvalues = [] 680 if facettypes[field] == 'float': 681 # Convert numbers to python numbers, and number ranges to a 682 # python tuple of two numbers. 683 for value, frequency in values.iteritems(): 684 if len(value) <= 9: 685 value1 = _log(_xapian.sortable_unserialise, value) 686 value2 = value1 687 else: 688 value1 = _log(_xapian.sortable_unserialise, value[:9]) 689 value2 = _log(_xapian.sortable_unserialise, value[9:]) 690 newvalues.append(((value1, value2), frequency)) 691 else: 692 for value, frequency in values.iteritems(): 693 newvalues.append((value, frequency)) 694 695 newvalues.sort() 696 if required: 697 required_results.append((score, field, newvalues)) 698 else: 699 results.append((score, field, newvalues)) 700 701 # Throw away any excess results if we have more required_results to 702 # insert. 703 maxfacets = maxfacets - len(required_results) 704 if maxfacets <= 0: 705 results = required_results 706 else: 707 results = results[:maxfacets] 708 results.extend(required_results) 709 results.sort() 710 711 # Throw away the scores because they're not meaningful outside this 712 # algorithm. 713 results = [(field, newvalues) for (score, field, newvalues) in results] 714 return results
715 716
717 -class SearchConnection(object):
718 """A connection to the search engine for searching. 719 720 The connection will access a view of the database. 721 722 """ 723 _qp_flags_base = _xapian.QueryParser.FLAG_LOVEHATE 724 _qp_flags_phrase = _xapian.QueryParser.FLAG_PHRASE 725 _qp_flags_synonym = (_xapian.QueryParser.FLAG_AUTO_SYNONYMS | 726 _xapian.QueryParser.FLAG_AUTO_MULTIWORD_SYNONYMS) 727 _qp_flags_bool = _xapian.QueryParser.FLAG_BOOLEAN 728 729 _index = None 730
731 - def __init__(self, indexpath):
732 """Create a new connection to the index for searching. 733 734 There may only an arbitrary number of search connections for a 735 particular database open at a given time (regardless of whether there 736 is a connection for indexing open as well). 737 738 If the database doesn't exist, an exception will be raised. 739 740 """ 741 self._index = _log(_xapian.Database, indexpath) 742 self._indexpath = indexpath 743 744 # Read the actions. 745 self._load_config() 746 747 self._close_handlers = []
748
749 - def __del__(self):
750 self.close()
751
752 - def append_close_handler(self, handler, userdata=None):
753 """Append a callback to the list of close handlers. 754 755 These will be called when the SearchConnection is closed. This happens 756 when the close() method is called, or when the SearchConnection object 757 is deleted. The callback will be passed two arguments: the path to the 758 SearchConnection object, and the userdata supplied to this method. 759 760 The handlers will be called in the order in which they were added. 761 762 The handlers will be called after the connection has been closed, so 763 cannot prevent it closing: their return value will be ignored. In 764 addition, they should not raise any exceptions. 765 766 """ 767 self._close_handlers.append((handler, userdata))
768
769 - def _get_sort_type(self, field):
770 """Get the sort type that should be used for a given field. 771 772 """ 773 try: 774 actions = self._field_actions[field]._actions 775 except KeyError: 776 actions = {} 777 for action, kwargslist in actions.iteritems(): 778 if action == FieldActions.SORT_AND_COLLAPSE: 779 for kwargs in kwargslist: 780 return kwargs['type']
781
782 - def _load_config(self):
783 """Load the configuration for the database. 784 785 """ 786 # Note: this code is basically duplicated in the IndexerConnection 787 # class. Move it to a shared location. 788 assert self._index is not None 789 790 config_str = _log(self._index.get_metadata, '_xappy_config') 791 if len(config_str) == 0: 792 self._field_actions = {} 793 self._field_mappings = _fieldmappings.FieldMappings() 794 self._facet_hierarchy = {} 795 self._facet_query_table = {} 796 return 797 798 try: 799 (self._field_actions, mappings, self._facet_hierarchy, self._facet_query_table, self._next_docid) = _cPickle.loads(config_str) 800 except ValueError: 801 # Backwards compatibility - configuration used to lack _facet_hierarchy and _facet_query_table 802 (self._field_actions, mappings, self._next_docid) = _cPickle.loads(config_str) 803 self._facet_hierarchy = {} 804 self._facet_query_table = {} 805 self._field_mappings = _fieldmappings.FieldMappings(mappings)
806
807 - def reopen(self):
808 """Reopen the connection. 809 810 This updates the revision of the index which the connection references 811 to the latest flushed revision. 812 813 """ 814 if self._index is None: 815 raise _errors.SearchError("SearchConnection has been closed") 816 self._index.reopen() 817 # Re-read the actions. 818 self._load_config()
819
820 - def close(self):
821 """Close the connection to the database. 822 823 It is important to call this method before allowing the class to be 824 garbage collected to ensure that the connection is cleaned up promptly. 825 826 No other methods may be called on the connection after this has been 827 called. (It is permissible to call close() multiple times, but 828 only the first call will have any effect.) 829 830 If an exception occurs, the database will be closed, but changes since 831 the last call to flush may be lost. 832 833 """ 834 if self._index is None: 835 return 836 837 # Remember the index path 838 indexpath = self._indexpath 839 840 # There is currently no "close()" method for xapian databases, so 841 # we have to rely on the garbage collector. Since we never copy 842 # the _index property out of this class, there should be no cycles, 843 # so the standard python implementation should garbage collect 844 # _index straight away. A close() method is planned to be added to 845 # xapian at some point - when it is, we should call it here to make 846 # the code more robust. 847 self._index = None 848 self._indexpath = None 849 self._field_actions = None 850 self._field_mappings = None 851 852 # Call the close handlers. 853 for handler, userdata in self._close_handlers: 854 try: 855 handler(indexpath, userdata) 856 except Exception, e: 857 import sys, traceback 858 print >>sys.stderr, "WARNING: unhandled exception in handler called by SearchConnection.close(): %s" % traceback.format_exception_only(type(e), e)
859
860 - def get_doccount(self):
861 """Count the number of documents in the database. 862 863 This count will include documents which have been added or removed but 864 not yet flushed(). 865 866 """ 867 if self._index is None: 868 raise _errors.SearchError("SearchConnection has been closed") 869 return self._index.get_doccount()
870 871 OP_AND = _xapian.Query.OP_AND 872 OP_OR = _xapian.Query.OP_OR
873 - def query_composite(self, operator, queries):
874 """Build a composite query from a list of queries. 875 876 The queries are combined with the supplied operator, which is either 877 SearchConnection.OP_AND or SearchConnection.OP_OR. 878 879 """ 880 if self._index is None: 881 raise _errors.SearchError("SearchConnection has been closed") 882 return _log(_xapian.Query, operator, list(queries))
883
884 - def query_multweight(self, query, multiplier):
885 """Build a query which modifies the weights of a subquery. 886 887 This produces a query which returns the same documents as the subquery, 888 and in the same order, but with the weights assigned to each document 889 multiplied by the value of "multiplier". "multiplier" may be any floating 890 point value, but negative values will be clipped to 0, since Xapian 891 doesn't support negative weights. 892 893 This can be useful when producing queries to be combined with 894 query_composite, because it allows the relative importance of parts of 895 the query to be adjusted. 896 897 """ 898 return _log(_xapian.Query, _xapian.Query.OP_SCALE_WEIGHT, query, multiplier)
899
900 - def query_filter(self, query, filter, exclude=False):
901 """Filter a query with another query. 902 903 If exclude is False (or not specified), documents will only match the 904 resulting query if they match the both the first and second query: the 905 results of the first query are "filtered" to only include those which 906 also match the second query. 907 908 If exclude is True, documents will only match the resulting query if 909 they match the first query, but not the second query: the results of 910 the first query are "filtered" to only include those which do not match 911 the second query. 912 913 Documents will always be weighted according to only the first query. 914 915 - `query`: The query to filter. 916 - `filter`: The filter to apply to the query. 917 - `exclude`: If True, the sense of the filter is reversed - only 918 documents which do not match the second query will be returned. 919 920 """ 921 if self._index is None: 922 raise _errors.SearchError("SearchConnection has been closed") 923 if not isinstance(filter, _xapian.Query): 924 raise _errors.SearchError("Filter must be a Xapian Query object") 925 if exclude: 926 return _log(_xapian.Query, _xapian.Query.OP_AND_NOT, query, filter) 927 else: 928 return _log(_xapian.Query, _xapian.Query.OP_FILTER, query, filter)
929
930 - def query_adjust(self, primary, secondary):
931 """Adjust the weights of one query with a secondary query. 932 933 Documents will be returned from the resulting query if and only if they 934 match the primary query (specified by the "primary" parameter). 935 However, the weights (and hence, the relevance rankings) of the 936 documents will be adjusted by adding weights from the secondary query 937 (specified by the "secondary" parameter). 938 939 """ 940 if self._index is None: 941 raise _errors.SearchError("SearchConnection has been closed") 942 return _log(_xapian.Query, _xapian.Query.OP_AND_MAYBE, primary, secondary)
943
944 - def query_range(self, field, begin, end):
945 """Create a query for a range search. 946 947 This creates a query which matches only those documents which have a 948 field value in the specified range. 949 950 Begin and end must be appropriate values for the field, according to 951 the 'type' parameter supplied to the SORTABLE action for the field. 952 953 The begin and end values are both inclusive - any documents with a 954 value equal to begin or end will be returned (unless end is less than 955 begin, in which case no documents will be returned). 956 957 Begin or end may be set to None in order to create an open-ended 958 range. (They may also both be set to None, which will generate a query 959 which matches all documents containing any value for the field.) 960 961 """ 962 if self._index is None: 963 raise _errors.SearchError("SearchConnection has been closed") 964 965 if begin is None and end is None: 966 # Return a "match everything" query 967 return _log(_xapian.Query, '') 968 969 try: 970 slot = self._field_mappings.get_slot(field, 'collsort') 971 except KeyError: 972 # Return a "match nothing" query 973 return _log(_xapian.Query) 974 975 sorttype = self._get_sort_type(field) 976 marshaller = SortableMarshaller(False) 977 fn = marshaller.get_marshall_function(field, sorttype) 978 979 if begin is not None: 980 begin = fn(field, begin) 981 if end is not None: 982 end = fn(field, end) 983 984 if begin is None: 985 return _log(_xapian.Query, _xapian.Query.OP_VALUE_LE, slot, end) 986 987 if end is None: 988 return _log(_xapian.Query, _xapian.Query.OP_VALUE_GE, slot, begin) 989 990 return _log(_xapian.Query, _xapian.Query.OP_VALUE_RANGE, slot, begin, end)
991
992 - def query_facet(self, field, val):
993 """Create a query for a facet value. 994 995 This creates a query which matches only those documents which have a 996 facet value in the specified range. 997 998 For a numeric range facet, val should be a tuple holding the start and 999 end of the range, or a comma separated string holding two floating 1000 point values. For other facets, val should be the value to look 1001 for. 1002 1003 The start and end values are both inclusive - any documents with a 1004 value equal to start or end will be returned (unless end is less than 1005 start, in which case no documents will be returned). 1006 1007 """ 1008 if self._index is None: 1009 raise _errors.SearchError("SearchConnection has been closed") 1010 if 'facets' in _checkxapian.missing_features: 1011 raise errors.SearchError("Facets unsupported with this release of xapian") 1012 1013 try: 1014 actions = self._field_actions[field]._actions 1015 except KeyError: 1016 actions = {} 1017 facettype = None 1018 for action, kwargslist in actions.iteritems(): 1019 if action == FieldActions.FACET: 1020 for kwargs in kwargslist: 1021 facettype = kwargs.get('type', None) 1022 if facettype is not None: 1023 break 1024 if facettype is not None: 1025 break 1026 1027 if facettype == 'float': 1028 if isinstance(val, basestring): 1029 val = [float(v) for v in val.split(',', 2)] 1030 assert(len(val) == 2) 1031 try: 1032 slot = self._field_mappings.get_slot(field, 'facet') 1033 except KeyError: 1034 return _log(_xapian.Query) 1035 # FIXME - check that sorttype == self._get_sort_type(field) 1036 sorttype = 'float' 1037 marshaller = SortableMarshaller(False) 1038 fn = marshaller.get_marshall_function(field, sorttype) 1039 begin = fn(field, val[0]) 1040 end = fn(field, val[1]) 1041 return _log(_xapian.Query, _xapian.Query.OP_VALUE_RANGE, slot, begin, end) 1042 else: 1043 assert(facettype == 'string' or facettype is None) 1044 prefix = self._field_mappings.get_prefix(field) 1045 return _log(_xapian.Query, prefix + val.lower())
1046 1047
1048 - def _prepare_queryparser(self, allow, deny, default_op, default_allow, 1049 default_deny):
1050 """Prepare (and return) a query parser using the specified fields and 1051 operator. 1052 1053 """ 1054 if self._index is None: 1055 raise _errors.SearchError("SearchConnection has been closed") 1056 1057 if isinstance(allow, basestring): 1058 allow = (allow, ) 1059 if isinstance(deny, basestring): 1060 deny = (deny, ) 1061 if allow is not None and len(allow) == 0: 1062 allow = None 1063 if deny is not None and len(deny) == 0: 1064 deny = None 1065 if allow is not None and deny is not None: 1066 raise _errors.SearchError("Cannot specify both `allow` and `deny` " 1067 "(got %r and %r)" % (allow, deny)) 1068 1069 if isinstance(default_allow, basestring): 1070 default_allow = (default_allow, ) 1071 if isinstance(default_deny, basestring): 1072 default_deny = (default_deny, ) 1073 if default_allow is not None and len(default_allow) == 0: 1074 default_allow = None 1075 if default_deny is not None and len(default_deny) == 0: 1076 default_deny = None 1077 if default_allow is not None and default_deny is not None: 1078 raise _errors.SearchError("Cannot specify both `default_allow` and `default_deny` " 1079 "(got %r and %r)" % (default_allow, default_deny)) 1080 1081 qp = _log(_xapian.QueryParser) 1082 qp.set_database(self._index) 1083 qp.set_default_op(default_op) 1084 1085 if allow is None: 1086 allow = [key for key in self._field_actions] 1087 if deny is not None: 1088 allow = [key for key in allow if key not in deny] 1089 1090 for field in allow: 1091 try: 1092 actions = self._field_actions[field]._actions 1093 except KeyError: 1094 actions = {} 1095 for action, kwargslist in actions.iteritems(): 1096 if action == FieldActions.INDEX_EXACT: 1097 # FIXME - need patched version of xapian to add exact prefixes 1098 #qp.add_exact_prefix(field, self._field_mappings.get_prefix(field)) 1099 qp.add_prefix(field, self._field_mappings.get_prefix(field)) 1100 if action == FieldActions.INDEX_FREETEXT: 1101 allow_field_specific = True 1102 for kwargs in kwargslist: 1103 allow_field_specific = allow_field_specific or kwargs.get('allow_field_specific', True) 1104 if not allow_field_specific: 1105 continue 1106 qp.add_prefix(field, self._field_mappings.get_prefix(field)) 1107 for kwargs in kwargslist: 1108 try: 1109 lang = kwargs['language'] 1110 my_stemmer = _log(_xapian.Stem, lang) 1111 qp.my_stemmer = my_stemmer 1112 qp.set_stemmer(my_stemmer) 1113 qp.set_stemming_strategy(qp.STEM_SOME) 1114 except KeyError: 1115 pass 1116 1117 if default_allow is not None or default_deny is not None: 1118 if default_allow is None: 1119 default_allow = [key for key in self._field_actions] 1120 if default_deny is not None: 1121 default_allow = [key for key in default_allow if key not in default_deny] 1122 for field in default_allow: 1123 try: 1124 actions = self._field_actions[field]._actions 1125 except KeyError: 1126 actions = {} 1127 for action, kwargslist in actions.iteritems(): 1128 if action == FieldActions.INDEX_FREETEXT: 1129 qp.add_prefix('', self._field_mappings.get_prefix(field)) 1130 # FIXME - set stemming options for the default prefix 1131 1132 return qp
1133
1134 - def _query_parse_with_prefix(self, qp, string, flags, prefix):
1135 """Parse a query, with an optional prefix. 1136 1137 """ 1138 if prefix is None: 1139 return qp.parse_query(string, flags) 1140 else: 1141 return qp.parse_query(string, flags, prefix)
1142
1143 - def _query_parse_with_fallback(self, qp, string, prefix=None):
1144 """Parse a query with various flags. 1145 1146 If the initial boolean pass fails, fall back to not using boolean 1147 operators. 1148 1149 """ 1150 try: 1151 q1 = self._query_parse_with_prefix(qp, string, 1152 self._qp_flags_base | 1153 self._qp_flags_phrase | 1154 self._qp_flags_synonym | 1155 self._qp_flags_bool, 1156 prefix) 1157 except _xapian.QueryParserError, e: 1158 # If we got a parse error, retry without boolean operators (since 1159 # these are the usual cause of the parse error). 1160 q1 = self._query_parse_with_prefix(qp, string, 1161 self._qp_flags_base | 1162 self._qp_flags_phrase | 1163 self._qp_flags_synonym, 1164 prefix) 1165 1166 qp.set_stemming_strategy(qp.STEM_NONE) 1167 try: 1168 q2 = self._query_parse_with_prefix(qp, string, 1169 self._qp_flags_base | 1170 self._qp_flags_bool, 1171 prefix) 1172 except _xapian.QueryParserError, e: 1173 # If we got a parse error, retry without boolean operators (since 1174 # these are the usual cause of the parse error). 1175 q2 = self._query_parse_with_prefix(qp, string, 1176 self._qp_flags_base, 1177 prefix) 1178 1179 return _log(_xapian.Query, _xapian.Query.OP_AND_MAYBE, q1, q2)
1180
1181 - def query_parse(self, string, allow=None, deny=None, default_op=OP_AND, 1182 default_allow=None, default_deny=None):
1183 """Parse a query string. 1184 1185 This is intended for parsing queries entered by a user. If you wish to 1186 combine structured queries, it is generally better to use the other 1187 query building methods, such as `query_composite` (though you may wish 1188 to create parts of the query to combine with such methods with this 1189 method). 1190 1191 The string passed to this method can have various operators in it. In 1192 particular, it may contain field specifiers (ie, field names, followed 1193 by a colon, followed by some text to search for in that field). For 1194 example, if "author" is a field in the database, the search string 1195 could contain "author:richard", and this would be interpreted as 1196 "search for richard in the author field". By default, any fields in 1197 the database which are indexed with INDEX_EXACT or INDEX_FREETEXT will 1198 be available for field specific searching in this way - however, this 1199 can be modified using the "allow" or "deny" parameters, and also by the 1200 allow_field_specific tag on INDEX_FREETEXT fields. 1201 1202 Any text which isn't prefixed by a field specifier is used to search 1203 the "default set" of fields. By default, this is the full set of 1204 fields in the database which are indexed with INDEX_FREETEXT and for 1205 which the search_by_default flag set (ie, if the text is found in any 1206 of those fields, the query will match). However, this may be modified 1207 with the "default_allow" and "default_deny" parameters. (Note that 1208 fields which are indexed with INDEX_EXACT aren't allowed to be used in 1209 the default list of fields.) 1210 1211 - `string`: The string to parse. 1212 - `allow`: A list of fields to allow in the query. 1213 - `deny`: A list of fields not to allow in the query. 1214 - `default_op`: The default operator to combine query terms with. 1215 - `default_allow`: A list of fields to search for by default. 1216 - `default_deny`: A list of fields not to search for by default. 1217 1218 Only one of `allow` and `deny` may be specified. 1219 1220 Only one of `default_allow` and `default_deny` may be specified. 1221 1222 If any of the entries in `allow` are not present in the configuration 1223 for the database, or are not specified for indexing (either as 1224 INDEX_EXACT or INDEX_FREETEXT), they will be ignored. If any of the 1225 entries in `deny` are not present in the configuration for the 1226 database, they will be ignored. 1227 1228 Returns a Query object, which may be passed to the search() method, or 1229 combined with other queries. 1230 1231 """ 1232 qp = self._prepare_queryparser(allow, deny, default_op, default_allow, 1233 default_deny) 1234 return self._query_parse_with_fallback(qp, string)
1235
1236 - def query_field(self, field, value, default_op=OP_AND):
1237 """A query for a single field. 1238 1239 """ 1240 if self._index is None: 1241 raise _errors.SearchError("SearchConnection has been closed") 1242 try: 1243 actions = self._field_actions[field]._actions 1244 except KeyError: 1245 actions = {} 1246 1247 # need to check on field type, and stem / split as appropriate 1248 for action, kwargslist in actions.iteritems(): 1249 if action in (FieldActions.INDEX_EXACT, 1250 FieldActions.TAG, 1251 FieldActions.FACET,): 1252 prefix = self._field_mappings.get_prefix(field) 1253 if len(value) > 0: 1254 chval = ord(value[0]) 1255 if chval >= ord('A') and chval <= ord('Z'): 1256 prefix = prefix + ':' 1257 return _log(_xapian.Query, prefix + value) 1258 if action == FieldActions.INDEX_FREETEXT: 1259 qp = _log(_xapian.QueryParser) 1260 qp.set_default_op(default_op) 1261 prefix = self._field_mappings.get_prefix(field) 1262 for kwargs in kwargslist: 1263 try: 1264 lang = kwargs['language'] 1265 qp.set_stemmer(_log(_xapian.Stem, lang)) 1266 qp.set_stemming_strategy(qp.STEM_SOME) 1267 except KeyError: 1268 pass 1269 return self._query_parse_with_fallback(qp, value, prefix) 1270 1271 return _log(_xapian.Query)
1272
1273 - def query_similar(self, ids, allow=None, deny=None, simterms=10):
1274 """Get a query which returns documents which are similar to others. 1275 1276 The list of document IDs to base the similarity search on is given in 1277 `ids`. This should be an iterable, holding a list of strings. If 1278 any of the supplied IDs cannot be found in the database, they will be 1279 ignored. (If no IDs can be found in the database, the resulting query 1280 will not match any documents.) 1281 1282 By default, all fields which have been indexed for freetext searching 1283 will be used for the similarity calculation. The list of fields used 1284 for this can be customised using the `allow` and `deny` parameters 1285 (only one of which may be specified): 1286 1287 - `allow`: A list of fields to base the similarity calculation on. 1288 - `deny`: A list of fields not to base the similarity calculation on. 1289 - `simterms`: Number of terms to use for the similarity calculation. 1290 1291 For convenience, any of `ids`, `allow`, or `deny` may be strings, which 1292 will be treated the same as a list of length 1. 1293 1294 Regardless of the setting of `allow` and `deny`, only fields which have 1295 been indexed for freetext searching will be used for the similarity 1296 measure - all other fields will always be ignored for this purpose. 1297 1298 """ 1299 eterms, prefixes = self._get_eterms(ids, allow, deny, simterms) 1300 1301 # Use the "elite set" operator, which chooses the terms with the 1302 # highest query weight to use. 1303 q = _log(_xapian.Query, _xapian.Query.OP_ELITE_SET, eterms, simterms) 1304 return q
1305
1306 - def significant_terms(self, ids, maxterms=10, allow=None, deny=None):
1307 """Get a set of "significant" terms for a document, or documents. 1308 1309 This has a similar interface to query_similar(): it takes a list of 1310 ids, and an optional specification of a set of fields to consider. 1311 Instead of returning a query, it returns a list of terms from the 1312 document (or documents), which appear "significant". Roughly, 1313 in this situation significant means that the terms occur more 1314 frequently in the specified document than in the rest of the corpus. 1315 1316 The list is in decreasing order of "significance". 1317 1318 By default, all terms related to fields which have been indexed for 1319 freetext searching will be considered for the list of significant 1320 terms. The list of fields used for this can be customised using the 1321 `allow` and `deny` parameters (only one of which may be specified): 1322 1323 - `allow`: A list of fields to consider. 1324 - `deny`: A list of fields not to consider. 1325 1326 For convenience, any of `ids`, `allow`, or `deny` may be strings, which 1327 will be treated the same as a list of length 1. 1328 1329 Regardless of the setting of `allow` and `deny`, only fields which have 1330 been indexed for freetext searching will be considered - all other 1331 fields will always be ignored for this purpose. 1332 1333 The maximum number of terms to return may be specified by the maxterms 1334 parameter. 1335 1336 """ 1337 eterms, prefixes = self._get_eterms(ids, allow, deny, maxterms) 1338 terms = [] 1339 for term in eterms: 1340 pos = 0 1341 for char in term: 1342 if not char.isupper(): 1343 break 1344 pos += 1 1345 field = prefixes[term[:pos]] 1346 value = term[pos:] 1347 terms.append((field, value)) 1348 return terms
1349
1350 - def _get_eterms(self, ids, allow, deny, simterms):
1351 """Get a set of terms for an expand 1352 1353 """ 1354 if self._index is None: 1355 raise _errors.SearchError("SearchConnection has been closed") 1356 if allow is not None and deny is not None: 1357 raise _errors.SearchError("Cannot specify both `allow` and `deny`") 1358 1359 if isinstance(ids, basestring): 1360 ids = (ids, ) 1361 if isinstance(allow, basestring): 1362 allow = (allow, ) 1363 if isinstance(deny, basestring): 1364 deny = (deny, ) 1365 1366 # Set "allow" to contain a list of all the fields to use. 1367 if allow is None: 1368 allow = [key for key in self._field_actions] 1369 if deny is not None: 1370 allow = [key for key in allow if key not in deny] 1371 1372 # Set "prefixes" to contain a list of all the prefixes to use. 1373 prefixes = {} 1374 for field in allow: 1375 try: 1376 actions = self._field_actions[field]._actions 1377 except KeyError: 1378 actions = {} 1379 for action, kwargslist in actions.iteritems(): 1380 if action == FieldActions.INDEX_FREETEXT: 1381 prefixes[self._field_mappings.get_prefix(field)] = field 1382 1383 # Repeat the expand until we don't get a DatabaseModifiedError 1384 while True: 1385 try: 1386 eterms = self._perform_expand(ids, prefixes, simterms) 1387 break; 1388 except _xapian.DatabaseModifiedError, e: 1389 self.reopen() 1390 return eterms, prefixes
1391
1392 - class ExpandDecider(_xapian.ExpandDecider):
1393 - def __init__(self, prefixes):
1394 _xapian.ExpandDecider.__init__(self) 1395 self._prefixes = prefixes
1396
1397 - def __call__(self, term):
1398 pos = 0 1399 for char in term: 1400 if not char.isupper(): 1401 break 1402 pos += 1 1403 if term[:pos] in self._prefixes: 1404 return True 1405 return False
1406
1407 - def _perform_expand(self, ids, prefixes, simterms):
1408 """Perform an expand operation to get the terms for a similarity 1409 search, given a set of ids (and a set of prefixes to restrict the 1410 similarity operation to). 1411 1412 """ 1413 # Set idquery to be a query which returns the documents listed in 1414 # "ids". 1415 idquery = _log(_xapian.Query, _xapian.Query.OP_OR, ['Q' + id for id in ids]) 1416 1417 enq = _log(_xapian.Enquire, self._index) 1418 enq.set_query(idquery) 1419 rset = _log(_xapian.RSet) 1420 for id in ids: 1421 pl = self._index.postlist('Q' + id) 1422 try: 1423 xapid = pl.next() 1424 rset.add_document(xapid.docid) 1425 except StopIteration: 1426 pass 1427 1428 expanddecider = _log(self.ExpandDecider, prefixes) 1429 eset = enq.get_eset(simterms, rset, 0, 1.0, expanddecider) 1430 return [term.term for term in eset]
1431
1432 - def query_all(self):
1433 """A query which matches all the documents in the database. 1434 1435 """ 1436 return _log(_xapian.Query, '')
1437
1438 - def query_none(self):
1439 """A query which matches no documents in the database. 1440 1441 This may be useful as a placeholder in various situations. 1442 1443 """ 1444 return _log(_xapian.Query)
1445
1446 - def spell_correct(self, querystr, allow=None, deny=None, default_op=OP_AND, 1447 default_allow=None, default_deny=None):
1448 """Correct a query spelling. 1449 1450 This returns a version of the query string with any misspelt words 1451 corrected. 1452 1453 - `allow`: A list of fields to allow in the query. 1454 - `deny`: A list of fields not to allow in the query. 1455 - `default_op`: The default operator to combine query terms with. 1456 - `default_allow`: A list of fields to search for by default. 1457 - `default_deny`: A list of fields not to search for by default. 1458 1459 Only one of `allow` and `deny` may be specified. 1460 1461 Only one of `default_allow` and `default_deny` may be specified. 1462 1463 If any of the entries in `allow` are not present in the configuration 1464 for the database, or are not specified for indexing (either as 1465 INDEX_EXACT or INDEX_FREETEXT), they will be ignored. If any of the 1466 entries in `deny` are not present in the configuration for the 1467 database, they will be ignored. 1468 1469 Note that it is possible that the resulting spell-corrected query will 1470 still match no documents - the user should usually check that some 1471 documents are matched by the corrected query before suggesting it to 1472 users. 1473 1474 """ 1475 qp = self._prepare_queryparser(allow, deny, default_op, default_allow, 1476 default_deny) 1477 try: 1478 qp.parse_query(querystr, 1479 self._qp_flags_base | 1480 self._qp_flags_phrase | 1481 self._qp_flags_synonym | 1482 self._qp_flags_bool | 1483 qp.FLAG_SPELLING_CORRECTION) 1484 except _xapian.QueryParserError: 1485 qp.parse_query(querystr, 1486 self._qp_flags_base | 1487 self._qp_flags_phrase | 1488 self._qp_flags_synonym | 1489 qp.FLAG_SPELLING_CORRECTION) 1490 corrected = qp.get_corrected_query_string() 1491 if len(corrected) == 0: 1492 if isinstance(querystr, unicode): 1493 # Encode as UTF-8 for consistency - this happens automatically 1494 # to values passed to Xapian. 1495 return querystr.encode('utf-8') 1496 return querystr 1497 return corrected
1498
1499 - def can_collapse_on(self, field):
1500 """Check if this database supports collapsing on a specified field. 1501 1502 """ 1503 if self._index is None: 1504 raise _errors.SearchError("SearchConnection has been closed") 1505 try: 1506 self._field_mappings.get_slot(field, 'collsort') 1507 except KeyError: 1508 return False 1509 return True
1510
1511 - def can_sort_on(self, field):
1512 """Check if this database supports sorting on a specified field. 1513 1514 """ 1515 if self._index is None: 1516 raise _errors.SearchError("SearchConnection has been closed") 1517 try: 1518 self._field_mappings.get_slot(field, 'collsort') 1519 except KeyError: 1520 return False 1521 return True
1522
1523 - def _get_prefix_from_term(self, term):
1524 """Get the prefix of a term. 1525 1526 Prefixes are any initial capital letters, with the exception that R always 1527 ends a prefix, even if followed by capital letters. 1528 1529 """ 1530 for p in xrange(len(term)): 1531 if term[p].islower(): 1532 return term[:p] 1533 elif term[p] == 'R': 1534 return term[:p+1] 1535 return term
1536
1537 - def _facet_query_never(self, facet, query_type):
1538 """Check if a facet must never be returned by a particular query type. 1539 1540 Returns True if the facet must never be returned. 1541 1542 Returns False if the facet may be returned - either becuase there is no 1543 entry for the query type, or because the entry is not 1544 FacetQueryType_Never. 1545 1546 """ 1547 if query_type is None: 1548 return False 1549 if query_type not in self._facet_query_table: 1550 return False 1551 if facet not in self._facet_query_table[query_type]: 1552 return False 1553 return self._facet_query_table[query_type][facet] == _indexerconnection.IndexerConnection.FacetQueryType_Never
1554
1555 - def search(self, query, startrank, endrank, 1556 checkatleast=0, sortby=None, collapse=None, 1557 gettags=None, 1558 getfacets=None, allowfacets=None, denyfacets=None, usesubfacets=None, 1559 percentcutoff=None, weightcutoff=None, 1560 query_type=None):
1561 """Perform a search, for documents matching a query. 1562 1563 - `query` is the query to perform. 1564 - `startrank` is the rank of the start of the range of matching 1565 documents to return (ie, the result with this rank will be returned). 1566 ranks start at 0, which represents the "best" matching document. 1567 - `endrank` is the rank at the end of the range of matching documents 1568 to return. This is exclusive, so the result with this rank will not 1569 be returned. 1570 - `checkatleast` is the minimum number of results to check for: the 1571 estimate of the total number of matches will always be exact if 1572 the number of matches is less than `checkatleast`. A value of ``-1`` 1573 can be specified for the checkatleast parameter - this has the 1574 special meaning of "check all matches", and is equivalent to passing 1575 the result of get_doccount(). 1576 - `sortby` is the name of a field to sort by. It may be preceded by a 1577 '+' or a '-' to indicate ascending or descending order 1578 (respectively). If the first character is neither '+' or '-', the 1579 sort will be in ascending order. 1580 - `collapse` is the name of a field to collapse the result documents 1581 on. If this is specified, there will be at most one result in the 1582 result set for each value of the field. 1583 - `gettags` is the name of a field to count tag occurrences in, or a 1584 list of fields to do so. 1585 - `getfacets` is a boolean - if True, the matching documents will be 1586 examined to build up a list of the facet values contained in them. 1587 - `allowfacets` is a list of the fieldnames of facets to consider. 1588 - `denyfacets` is a list of fieldnames of facets which will not be 1589 considered. 1590 - `usesubfacets` is a boolean - if True, only top-level facets and 1591 subfacets of facets appearing in the query are considered (taking 1592 precedence over `allowfacets` and `denyfacets`). 1593 - `percentcutoff` is the minimum percentage a result must have to be 1594 returned. 1595 - `weightcutoff` is the minimum weight a result must have to be 1596 returned. 1597 - `query_type` is a value indicating the type of query being 1598 performed. If not None, the value is used to influence which facets 1599 are be returned by the get_suggested_facets() function. If the 1600 value of `getfacets` is False, it has no effect. 1601 1602 If neither 'allowfacets' or 'denyfacets' is specified, all fields 1603 holding facets will be considered (but see 'usesubfacets'). 1604 1605 """ 1606 if self._index is None: 1607 raise _errors.SearchError("SearchConnection has been closed") 1608 if 'facets' in _checkxapian.missing_features: 1609 if getfacets is not None or \ 1610 allowfacets is not None or \ 1611 denyfacets is not None or \ 1612 usesubfacets is not None or \ 1613 query_type is not None: 1614 raise errors.SearchError("Facets unsupported with this release of xapian") 1615 if 'tags' in _checkxapian.missing_features: 1616 if gettags is not None: 1617 raise errors.SearchError("Tags unsupported with this release of xapian") 1618 if checkatleast == -1: 1619 checkatleast = self._index.get_doccount() 1620 1621 enq = _log(_xapian.Enquire, self._index) 1622 enq.set_query(query) 1623 1624 if sortby is not None: 1625 asc = True 1626 if sortby[0] == '-': 1627 asc = False 1628 sortby = sortby[1:] 1629 elif sortby[0] == '+': 1630 sortby = sortby[1:] 1631 1632 try: 1633 slotnum = self._field_mappings.get_slot(sortby, 'collsort') 1634 except KeyError: 1635 raise _errors.SearchError("Field %r was not indexed for sorting" % sortby) 1636 1637 # Note: we invert the "asc" parameter, because xapian treats 1638 # "ascending" as meaning "higher values are better"; in other 1639 # words, it considers "ascending" to mean return results in 1640 # descending order. 1641 enq.set_sort_by_value_then_relevance(slotnum, not asc) 1642 1643 if collapse is not None: 1644 try: 1645 slotnum = self._field_mappings.get_slot(collapse, 'collsort') 1646 except KeyError: 1647 raise _errors.SearchError("Field %r was not indexed for collapsing" % collapse) 1648 enq.set_collapse_key(slotnum) 1649 1650 maxitems = max(endrank - startrank, 0) 1651 # Always check for at least one more result, so we can report whether 1652 # there are more matches. 1653 checkatleast = max(checkatleast, endrank + 1) 1654 1655 # Build the matchspy. 1656 matchspies = [] 1657 1658 # First, add a matchspy for any gettags fields 1659 if isinstance(gettags, basestring): 1660 if len(gettags) != 0: 1661 gettags = [gettags] 1662 tagspy = None 1663 if gettags is not None and len(gettags) != 0: 1664 tagspy = _log(_xapian.TermCountMatchSpy) 1665 for field in gettags: 1666 try: 1667 prefix = self._field_mappings.get_prefix(field) 1668 tagspy.add_prefix(prefix) 1669 except KeyError: 1670 raise _errors.SearchError("Field %r was not indexed for tagging" % field) 1671 matchspies.append(tagspy) 1672 1673 1674 # add a matchspy for facet selection here. 1675 facetspy = None 1676 facetfields = [] 1677 if getfacets: 1678 if allowfacets is not None and denyfacets is not None: 1679 raise _errors.SearchError("Cannot specify both `allowfacets` and `denyfacets`") 1680 if allowfacets is None: 1681 allowfacets = [key for key in self._field_actions] 1682 if denyfacets is not None: 1683 allowfacets = [key for key in allowfacets if key not in denyfacets] 1684 1685 # include None in queryfacets so a top-level facet will 1686 # satisfy self._facet_hierarchy.get(field) in queryfacets 1687 # (i.e. always include top-level facets) 1688 queryfacets = set([None]) 1689 if usesubfacets: 1690 # add facets used in the query to queryfacets 1691 termsiter = query.get_terms_begin() 1692 termsend = query.get_terms_end() 1693 while termsiter != termsend: 1694 prefix = self._get_prefix_from_term(termsiter.get_term()) 1695 field = self._field_mappings.get_fieldname_from_prefix(prefix) 1696 if field and FieldActions.FACET in self._field_actions[field]._actions: 1697 queryfacets.add(field) 1698 termsiter.next() 1699 1700 for field in allowfacets: 1701 try: 1702 actions = self._field_actions[field]._actions 1703 except KeyError: 1704 actions = {} 1705 for action, kwargslist in actions.iteritems(): 1706 if action == FieldActions.FACET: 1707 # filter out non-top-level facets that aren't subfacets 1708 # of a facet in the query 1709 if usesubfacets and self._facet_hierarchy.get(field) not in queryfacets: 1710 continue 1711 # filter out facets that should never be returned for the query type 1712 if self._facet_query_never(field, query_type): 1713 continue 1714 slot = self._field_mappings.get_slot(field, 'facet') 1715 if facetspy is None: 1716 facetspy = _log(_xapian.CategorySelectMatchSpy) 1717 facettype = None 1718 for kwargs in kwargslist: 1719 facettype = kwargs.get('type', None) 1720 if facettype is not None: 1721 break 1722 if facettype is None or facettype == 'string': 1723 facetspy.add_slot(slot, True) 1724 else: 1725 facetspy.add_slot(slot) 1726 facetfields.append((field, slot, kwargslist)) 1727 1728 if facetspy is None: 1729 # Set facetspy to False, to distinguish from no facet 1730 # calculation being performed. (This will prevent an 1731 # error being thrown when the list of suggested facets is 1732 # requested - instead, an empty list will be returned.) 1733 facetspy = False 1734 else: 1735 matchspies.append(facetspy) 1736 1737 1738 # Finally, build a single matchspy to pass to get_mset(). 1739 if len(matchspies) == 0: 1740 matchspy = None 1741 elif len(matchspies) == 1: 1742 matchspy = matchspies[0] 1743 else: 1744 matchspy = _log(_xapian.MultipleMatchDecider) 1745 for spy in matchspies: 1746 matchspy.append(spy) 1747 1748 enq.set_docid_order(enq.DONT_CARE) 1749 1750 # Set percentage and weight cutoffs 1751 if percentcutoff is not None or weightcutoff is not None: 1752 if percentcutoff is None: 1753 percentcutoff = 0 1754 if weightcutoff is None: 1755 weightcutoff = 0 1756 enq.set_cutoff(percentcutoff, weightcutoff) 1757 1758 # Repeat the search until we don't get a DatabaseModifiedError 1759 while True: 1760 try: 1761 if matchspy is None: 1762 mset = enq.get_mset(startrank, maxitems, checkatleast) 1763 else: 1764 mset = enq.get_mset(startrank, maxitems, checkatleast, 1765 None, None, matchspy) 1766 break 1767 except _xapian.DatabaseModifiedError, e: 1768 self.reopen() 1769 facet_hierarchy = None 1770 if usesubfacets: 1771 facet_hierarchy = self._facet_hierarchy 1772 1773 return SearchResults(self, enq, query, mset, self._field_mappings, 1774 tagspy, gettags, facetspy, facetfields, 1775 facet_hierarchy, 1776 self._facet_query_table.get(query_type))
1777
1778 - def iterids(self):
1779 """Get an iterator which returns all the ids in the database. 1780 1781 The unqiue_ids are currently returned in binary lexicographical sort 1782 order, but this should not be relied on. 1783 1784 Note that the iterator returned by this method may raise a 1785 xapian.DatabaseModifiedError exception if modifications are committed 1786 to the database while the iteration is in progress. If this happens, 1787 the search connection must be reopened (by calling reopen) and the 1788 iteration restarted. 1789 1790 """ 1791 if self._index is None: 1792 raise _errors.SearchError("SearchConnection has been closed") 1793 return _indexerconnection.PrefixedTermIter('Q', self._index.allterms())
1794
1795 - def get_document(self, id):
1796 """Get the document with the specified unique ID. 1797 1798 Raises a KeyError if there is no such document. Otherwise, it returns 1799 a ProcessedDocument. 1800 1801 """ 1802 if self._index is None: 1803 raise _errors.SearchError("SearchConnection has been closed") 1804 while True: 1805 try: 1806 postlist = self._index.postlist('Q' + id) 1807 try: 1808 plitem = postlist.next() 1809 except StopIteration: 1810 # Unique ID not found 1811 raise KeyError('Unique ID %r not found' % id) 1812 try: 1813 postlist.next() 1814 raise _errors.IndexerError("Multiple documents " #pragma: no cover 1815 "found with same unique ID") 1816 except StopIteration: 1817 # Only one instance of the unique ID found, as it should be. 1818 pass 1819 1820 result = ProcessedDocument(self._field_mappings) 1821 result.id = id 1822 result._doc = self._index.get_document(plitem.docid) 1823 return result 1824 except _xapian.DatabaseModifiedError, e: 1825 self.reopen()
1826
1827 - def iter_synonyms(self, prefix=""):
1828 """Get an iterator over the synonyms. 1829 1830 - `prefix`: if specified, only synonym keys with this prefix will be 1831 returned. 1832 1833 The iterator returns 2-tuples, in which the first item is the key (ie, 1834 a 2-tuple holding the term or terms which will be synonym expanded, 1835 followed by the fieldname specified (or None if no fieldname)), and the 1836 second item is a tuple of strings holding the synonyms for the first 1837 item. 1838 1839 These return values are suitable for the dict() builtin, so you can 1840 write things like: 1841 1842 >>> conn = _indexerconnection.IndexerConnection('foo') 1843 >>> conn.add_synonym('foo', 'bar') 1844 >>> conn.add_synonym('foo bar', 'baz') 1845 >>> conn.add_synonym('foo bar', 'foo baz') 1846 >>> conn.flush() 1847 >>> conn = SearchConnection('foo') 1848 >>> dict(conn.iter_synonyms()) 1849 {('foo', None): ('bar',), ('foo bar', None): ('baz', 'foo baz')} 1850 1851 """ 1852 if self._index is None: 1853 raise _errors.SearchError("SearchConnection has been closed") 1854 return _indexerconnection.SynonymIter(self._index, self._field_mappings, prefix)
1855
1856 - def get_metadata(self, key):
1857 """Get an item of metadata stored in the connection. 1858 1859 This returns a value stored by a previous call to 1860 IndexerConnection.set_metadata. 1861 1862 If the value is not found, this will return the empty string. 1863 1864 """ 1865 if self._index is None: 1866 raise _errors.IndexerError("SearchConnection has been closed") 1867 if not hasattr(self._index, 'get_metadata'): 1868 raise _errors.IndexerError("Version of xapian in use does not support metadata") 1869 return _log(self._index.get_metadata, key)
1870 1871 if __name__ == '__main__': 1872 import doctest, sys 1873 doctest.testmod (sys.modules[__name__]) 1874

xappy-0.5/docs/api/xappy.searchconnection.SearchConnection-class.html0000644000175000017500000020175611005555243025747 0ustar richardrichard xappy.searchconnection.SearchConnection
Package xappy :: Module searchconnection :: Class SearchConnection
[frames] | no frames]

Class SearchConnection

source code

object --+
         |
        SearchConnection

A connection to the search engine for searching.

The connection will access a view of the database.



Nested Classes
  ExpandDecider
Instance Methods
 
__init__(self, indexpath)
Create a new connection to the index for searching.
source code
 
__del__(self) source code
 
append_close_handler(self, handler, userdata=None)
Append a callback to the list of close handlers.
source code
 
reopen(self)
Reopen the connection.
source code
 
close(self)
Close the connection to the database.
source code
 
get_doccount(self)
Count the number of documents in the database.
source code
 
query_composite(self, operator, queries)
Build a composite query from a list of queries.
source code
 
query_multweight(self, query, multiplier)
Build a query which modifies the weights of a subquery.
source code
 
query_filter(self, query, filter, exclude=False)
Filter a query with another query.
source code
 
query_adjust(self, primary, secondary)
Adjust the weights of one query with a secondary query.
source code
 
query_range(self, field, begin, end)
Create a query for a range search.
source code
 
query_facet(self, field, val)
Create a query for a facet value.
source code
 
query_parse(self, string, allow=None, deny=None, default_op=0, default_allow=None, default_deny=None)
Parse a query string.
source code
 
query_field(self, field, value, default_op=0)
A query for a single field.
source code
 
query_similar(self, ids, allow=None, deny=None, simterms=10)
Get a query which returns documents which are similar to others.
source code
 
significant_terms(self, ids, maxterms=10, allow=None, deny=None)
Get a set of "significant" terms for a document, or documents.
source code
 
query_all(self)
A query which matches all the documents in the database.
source code
 
query_none(self)
A query which matches no documents in the database.
source code
 
spell_correct(self, querystr, allow=None, deny=None, default_op=0, default_allow=None, default_deny=None)
Correct a query spelling.
source code
 
can_collapse_on(self, field)
Check if this database supports collapsing on a specified field.
source code
 
can_sort_on(self, field)
Check if this database supports sorting on a specified field.
source code
 
search(self, query, startrank, endrank, checkatleast=0, sortby=None, collapse=None, gettags=None, getfacets=None, allowfacets=None, denyfacets=None, usesubfacets=None, percentcutoff=None, weightcutoff=None, query_type=None)
Perform a search, for documents matching a query.
source code
 
iterids(self)
Get an iterator which returns all the ids in the database.
source code
 
get_document(self, id)
Get the document with the specified unique ID.
source code
 
iter_synonyms(self, prefix='')
Get an iterator over the synonyms.
source code
 
get_metadata(self, key)
Get an item of metadata stored in the connection.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Class Variables
  OP_AND = 0
  OP_OR = 1
Properties

Inherited from object: __class__

Method Details

__init__(self, indexpath)
(Constructor)

source code 

Create a new connection to the index for searching.

There may only an arbitrary number of search connections for a particular database open at a given time (regardless of whether there is a connection for indexing open as well).

If the database doesn't exist, an exception will be raised.

Overrides: object.__init__

append_close_handler(self, handler, userdata=None)

source code 

Append a callback to the list of close handlers.

These will be called when the SearchConnection is closed. This happens when the close() method is called, or when the SearchConnection object is deleted. The callback will be passed two arguments: the path to the SearchConnection object, and the userdata supplied to this method.

The handlers will be called in the order in which they were added.

The handlers will be called after the connection has been closed, so cannot prevent it closing: their return value will be ignored. In addition, they should not raise any exceptions.

reopen(self)

source code 

Reopen the connection.

This updates the revision of the index which the connection references to the latest flushed revision.

close(self)

source code 

Close the connection to the database.

It is important to call this method before allowing the class to be garbage collected to ensure that the connection is cleaned up promptly.

No other methods may be called on the connection after this has been called. (It is permissible to call close() multiple times, but only the first call will have any effect.)

If an exception occurs, the database will be closed, but changes since the last call to flush may be lost.

get_doccount(self)

source code 

Count the number of documents in the database.

This count will include documents which have been added or removed but not yet flushed().

query_composite(self, operator, queries)

source code 

Build a composite query from a list of queries.

The queries are combined with the supplied operator, which is either SearchConnection.OP_AND or SearchConnection.OP_OR.

query_multweight(self, query, multiplier)

source code 

Build a query which modifies the weights of a subquery.

This produces a query which returns the same documents as the subquery, and in the same order, but with the weights assigned to each document multiplied by the value of "multiplier". "multiplier" may be any floating point value, but negative values will be clipped to 0, since Xapian doesn't support negative weights.

This can be useful when producing queries to be combined with query_composite, because it allows the relative importance of parts of the query to be adjusted.

query_filter(self, query, filter, exclude=False)

source code 

Filter a query with another query.

If exclude is False (or not specified), documents will only match the resulting query if they match the both the first and second query: the results of the first query are "filtered" to only include those which also match the second query.

If exclude is True, documents will only match the resulting query if they match the first query, but not the second query: the results of the first query are "filtered" to only include those which do not match the second query.

Documents will always be weighted according to only the first query.

  • query: The query to filter.
  • filter: The filter to apply to the query.
  • exclude: If True, the sense of the filter is reversed - only documents which do not match the second query will be returned.

query_adjust(self, primary, secondary)

source code 

Adjust the weights of one query with a secondary query.

Documents will be returned from the resulting query if and only if they match the primary query (specified by the "primary" parameter). However, the weights (and hence, the relevance rankings) of the documents will be adjusted by adding weights from the secondary query (specified by the "secondary" parameter).

query_range(self, field, begin, end)

source code 

Create a query for a range search.

This creates a query which matches only those documents which have a field value in the specified range.

Begin and end must be appropriate values for the field, according to the 'type' parameter supplied to the SORTABLE action for the field.

The begin and end values are both inclusive - any documents with a value equal to begin or end will be returned (unless end is less than begin, in which case no documents will be returned).

Begin or end may be set to None in order to create an open-ended range. (They may also both be set to None, which will generate a query which matches all documents containing any value for the field.)

query_facet(self, field, val)

source code 

Create a query for a facet value.

This creates a query which matches only those documents which have a facet value in the specified range.

For a numeric range facet, val should be a tuple holding the start and end of the range, or a comma separated string holding two floating point values. For other facets, val should be the value to look for.

The start and end values are both inclusive - any documents with a value equal to start or end will be returned (unless end is less than start, in which case no documents will be returned).

query_parse(self, string, allow=None, deny=None, default_op=0, default_allow=None, default_deny=None)

source code 

Parse a query string.

This is intended for parsing queries entered by a user. If you wish to combine structured queries, it is generally better to use the other query building methods, such as query_composite (though you may wish to create parts of the query to combine with such methods with this method).

The string passed to this method can have various operators in it. In particular, it may contain field specifiers (ie, field names, followed by a colon, followed by some text to search for in that field). For example, if "author" is a field in the database, the search string could contain "author:richard", and this would be interpreted as "search for richard in the author field". By default, any fields in the database which are indexed with INDEX_EXACT or INDEX_FREETEXT will be available for field specific searching in this way - however, this can be modified using the "allow" or "deny" parameters, and also by the allow_field_specific tag on INDEX_FREETEXT fields.

Any text which isn't prefixed by a field specifier is used to search the "default set" of fields. By default, this is the full set of fields in the database which are indexed with INDEX_FREETEXT and for which the search_by_default flag set (ie, if the text is found in any of those fields, the query will match). However, this may be modified with the "default_allow" and "default_deny" parameters. (Note that fields which are indexed with INDEX_EXACT aren't allowed to be used in the default list of fields.)

  • string: The string to parse.
  • allow: A list of fields to allow in the query.
  • deny: A list of fields not to allow in the query.
  • default_op: The default operator to combine query terms with.
  • default_allow: A list of fields to search for by default.
  • default_deny: A list of fields not to search for by default.

Only one of allow and deny may be specified.

Only one of default_allow and default_deny may be specified.

If any of the entries in allow are not present in the configuration for the database, or are not specified for indexing (either as INDEX_EXACT or INDEX_FREETEXT), they will be ignored. If any of the entries in deny are not present in the configuration for the database, they will be ignored.

Returns a Query object, which may be passed to the search() method, or combined with other queries.

query_similar(self, ids, allow=None, deny=None, simterms=10)

source code 

Get a query which returns documents which are similar to others.

The list of document IDs to base the similarity search on is given in ids. This should be an iterable, holding a list of strings. If any of the supplied IDs cannot be found in the database, they will be ignored. (If no IDs can be found in the database, the resulting query will not match any documents.)

By default, all fields which have been indexed for freetext searching will be used for the similarity calculation. The list of fields used for this can be customised using the allow and deny parameters (only one of which may be specified):

  • allow: A list of fields to base the similarity calculation on.
  • deny: A list of fields not to base the similarity calculation on.
  • simterms: Number of terms to use for the similarity calculation.

For convenience, any of ids, allow, or deny may be strings, which will be treated the same as a list of length 1.

Regardless of the setting of allow and deny, only fields which have been indexed for freetext searching will be used for the similarity measure - all other fields will always be ignored for this purpose.

significant_terms(self, ids, maxterms=10, allow=None, deny=None)

source code 

Get a set of "significant" terms for a document, or documents.

This has a similar interface to query_similar(): it takes a list of ids, and an optional specification of a set of fields to consider. Instead of returning a query, it returns a list of terms from the document (or documents), which appear "significant". Roughly, in this situation significant means that the terms occur more frequently in the specified document than in the rest of the corpus.

The list is in decreasing order of "significance".

By default, all terms related to fields which have been indexed for freetext searching will be considered for the list of significant terms. The list of fields used for this can be customised using the allow and deny parameters (only one of which may be specified):

  • allow: A list of fields to consider.
  • deny: A list of fields not to consider.

For convenience, any of ids, allow, or deny may be strings, which will be treated the same as a list of length 1.

Regardless of the setting of allow and deny, only fields which have been indexed for freetext searching will be considered - all other fields will always be ignored for this purpose.

The maximum number of terms to return may be specified by the maxterms parameter.

query_none(self)

source code 

A query which matches no documents in the database.

This may be useful as a placeholder in various situations.

spell_correct(self, querystr, allow=None, deny=None, default_op=0, default_allow=None, default_deny=None)

source code 

Correct a query spelling.

This returns a version of the query string with any misspelt words corrected.

  • allow: A list of fields to allow in the query.
  • deny: A list of fields not to allow in the query.
  • default_op: The default operator to combine query terms with.
  • default_allow: A list of fields to search for by default.
  • default_deny: A list of fields not to search for by default.

Only one of allow and deny may be specified.

Only one of default_allow and default_deny may be specified.

If any of the entries in allow are not present in the configuration for the database, or are not specified for indexing (either as INDEX_EXACT or INDEX_FREETEXT), they will be ignored. If any of the entries in deny are not present in the configuration for the database, they will be ignored.

Note that it is possible that the resulting spell-corrected query will still match no documents - the user should usually check that some documents are matched by the corrected query before suggesting it to users.

search(self, query, startrank, endrank, checkatleast=0, sortby=None, collapse=None, gettags=None, getfacets=None, allowfacets=None, denyfacets=None, usesubfacets=None, percentcutoff=None, weightcutoff=None, query_type=None)

source code 

Perform a search, for documents matching a query.

  • query is the query to perform.
  • startrank is the rank of the start of the range of matching documents to return (ie, the result with this rank will be returned). ranks start at 0, which represents the "best" matching document.
  • endrank is the rank at the end of the range of matching documents to return. This is exclusive, so the result with this rank will not be returned.
  • checkatleast is the minimum number of results to check for: the estimate of the total number of matches will always be exact if the number of matches is less than checkatleast. A value of -1 can be specified for the checkatleast parameter - this has the special meaning of "check all matches", and is equivalent to passing the result of get_doccount().
  • sortby is the name of a field to sort by. It may be preceded by a '+' or a '-' to indicate ascending or descending order (respectively). If the first character is neither '+' or '-', the sort will be in ascending order.
  • collapse is the name of a field to collapse the result documents on. If this is specified, there will be at most one result in the result set for each value of the field.
  • gettags is the name of a field to count tag occurrences in, or a list of fields to do so.
  • getfacets is a boolean - if True, the matching documents will be examined to build up a list of the facet values contained in them.
  • allowfacets is a list of the fieldnames of facets to consider.
  • denyfacets is a list of fieldnames of facets which will not be considered.
  • usesubfacets is a boolean - if True, only top-level facets and subfacets of facets appearing in the query are considered (taking precedence over allowfacets and denyfacets).
  • percentcutoff is the minimum percentage a result must have to be returned.
  • weightcutoff is the minimum weight a result must have to be returned.
  • query_type is a value indicating the type of query being performed. If not None, the value is used to influence which facets are be returned by the get_suggested_facets() function. If the value of getfacets is False, it has no effect.

If neither 'allowfacets' or 'denyfacets' is specified, all fields holding facets will be considered (but see 'usesubfacets').

iterids(self)

source code 

Get an iterator which returns all the ids in the database.

The unqiue_ids are currently returned in binary lexicographical sort order, but this should not be relied on.

Note that the iterator returned by this method may raise a xapian.DatabaseModifiedError exception if modifications are committed to the database while the iteration is in progress. If this happens, the search connection must be reopened (by calling reopen) and the iteration restarted.

get_document(self, id)

source code 

Get the document with the specified unique ID.

Raises a KeyError if there is no such document. Otherwise, it returns a ProcessedDocument.

iter_synonyms(self, prefix='')

source code 

Get an iterator over the synonyms.

  • prefix: if specified, only synonym keys with this prefix will be returned.

The iterator returns 2-tuples, in which the first item is the key (ie, a 2-tuple holding the term or terms which will be synonym expanded, followed by the fieldname specified (or None if no fieldname)), and the second item is a tuple of strings holding the synonyms for the first item.

These return values are suitable for the dict() builtin, so you can write things like:

>>> conn = _indexerconnection.IndexerConnection('foo')
>>> conn.add_synonym('foo', 'bar')
>>> conn.add_synonym('foo bar', 'baz')
>>> conn.add_synonym('foo bar', 'foo baz')
>>> conn.flush()
>>> conn = SearchConnection('foo')
>>> dict(conn.iter_synonyms())
{('foo', None): ('bar',), ('foo bar', None): ('baz', 'foo baz')}

get_metadata(self, key)

source code 

Get an item of metadata stored in the connection.

This returns a value stored by a previous call to IndexerConnection.set_metadata.

If the value is not found, this will return the empty string.


xappy-0.5/docs/api/xappy.searchconnection.SearchConnection.ExpandDecider-class.html0000644000175000017500000002265111005555243030440 0ustar richardrichard xappy.searchconnection.SearchConnection.ExpandDecider
Package xappy :: Module searchconnection :: Class SearchConnection :: Class ExpandDecider
[frames] | no frames]

Class ExpandDecider

source code

          object --+    
                   |    
xapian.ExpandDecider --+
                       |
                      SearchConnection.ExpandDecider

Instance Methods
 
__init__(self, prefixes)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
__call__(self, term) source code

Inherited from xapian.ExpandDecider: __disown__, __repr__, __swig_destroy__

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __str__

Properties

Inherited from xapian.ExpandDecider: thisown

Inherited from object: __class__

Method Details

__init__(self, prefixes)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: xapian.ExpandDecider.__init__

__call__(self, term)
(Call operator)

source code 
Overrides: xapian.ExpandDecider.__call__

xappy-0.5/docs/api/xappy.searchconnection.SearchResult-class.html0000644000175000017500000004650211005555243025122 0ustar richardrichard xappy.searchconnection.SearchResult
Package xappy :: Module searchconnection :: Class SearchResult
[frames] | no frames]

Class SearchResult

source code

                      object --+    
                               |    
datastructures.ProcessedDocument --+
                                   |
                                  SearchResult

A result from a search.

As well as being a ProcessedDocument representing the document in the database, the result has several members which may be used to get information about how well the document matches the search:

  • rank: The rank of the document in the search results, starting at 0 (ie, 0 is the "top" result, 1 is the second result, etc).
  • weight: A floating point number indicating the weight of the result document. The value is only meaningful relative to other results for a given search - a different search, or the same search with a different database, may give an entirely different scale to the weights. This should not usually be displayed to users, but may be useful if trying to perform advanced reweighting operations on search results.
  • percent: A percentage value for the weight of a document. This is just a rescaled form of the weight member. It doesn't represent any kind of probability value; the only real meaning of the numbers is that, within a single set of results, a document with a higher percentage corresponds to a better match. Because the percentage doesn't really represent a probability, or a confidence value, it is probably unhelpful to display it to most users, since they tend to place an over emphasis on its meaning. However, it is included because it may be useful occasionally.


Instance Methods
 
__init__(self, msetitem, results)
Create a ProcessedDocument.
source code
 
summarise(self, field, maxlen=600, hl=('<b>', '</b>'), query=None)
Return a summarised version of the field specified.
source code
 
highlight(self, field, hl=('<b>', '</b>'), strip_tags=False, query=None)
Return a highlighted version of the field specified.
source code
 
__repr__(self)
repr(x)
source code

Inherited from datastructures.ProcessedDocument: add_term, add_value, get_value, prepare

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __str__

Properties

Inherited from datastructures.ProcessedDocument: data, id

Inherited from object: __class__

Method Details

__init__(self, msetitem, results)
(Constructor)

source code 

Create a ProcessedDocument.

fieldmappings is the configuration from a database connection used lookup the configuration to use to store each field.

If supplied, xapdoc is a Xapian document to store in the processed document. Otherwise, a new Xapian document is created.

Overrides: datastructures.ProcessedDocument.__init__
(inherited documentation)

summarise(self, field, maxlen=600, hl=('<b>', '</b>'), query=None)

source code 

Return a summarised version of the field specified.

This will return a summary of the contents of the field stored in the search result, with words which match the query highlighted.

The maximum length of the summary (in characters) may be set using the maxlen parameter.

The return value will be a string holding the summary, with highlighting applied. If there are multiple instances of the field in the document, the instances will be joined with a newline character.

To turn off highlighting, set hl to None. Each highlight will consist of the first entry in the hl list being placed before the word, and the second entry in the hl list being placed after the word.

Any XML or HTML style markup tags in the field will be stripped before the summarisation algorithm is applied.

If query is supplied, it should contain a Query object, as returned from SearchConnection.query_parse() or related methods, which will be used as the basis of the summarisation and highlighting rather than the query which was used for the search.

Raises KeyError if the field is not known.

highlight(self, field, hl=('<b>', '</b>'), strip_tags=False, query=None)

source code 

Return a highlighted version of the field specified.

This will return all the contents of the field stored in the search result, with words which match the query highlighted.

The return value will be a list of strings (corresponding to the list of strings which is the raw field data).

Each highlight will consist of the first entry in the hl list being placed before the word, and the second entry in the hl list being placed after the word.

If strip_tags is True, any XML or HTML style markup tags in the field will be stripped before highlighting is applied.

If query is supplied, it should contain a Query object, as returned from SearchConnection.query_parse() or related methods, which will be used as the basis of the summarisation and highlighting rather than the query which was used for the search.

Raises KeyError if the field is not known.

__repr__(self)
(Representation operator)

source code 
repr(x)
Overrides: datastructures.ProcessedDocument.__repr__

xappy-0.5/docs/api/xappy.searchconnection.SearchResultIter-class.html0000644000175000017500000002023111005555243025735 0ustar richardrichard xappy.searchconnection.SearchResultIter
Package xappy :: Module searchconnection :: Class SearchResultIter
[frames] | no frames]

Class SearchResultIter

source code

object --+
         |
        SearchResultIter

An iterator over a set of results from a search.

Instance Methods
 
__init__(self, results, order)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
next(self) source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __repr__, __setattr__, __str__

Properties

Inherited from object: __class__

Method Details

__init__(self, results, order)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

xappy-0.5/docs/api/xappy.searchconnection.SearchResults-class.html0000644000175000017500000007302211005555243025302 0ustar richardrichard xappy.searchconnection.SearchResults
Package xappy :: Module searchconnection :: Class SearchResults
[frames] | no frames]

Class SearchResults

source code

object --+
         |
        SearchResults

A set of results of a search.

Instance Methods
 
__init__(self, conn, enq, query, mset, fieldmappings, tagspy, tagfields, facetspy, facetfields, facethierarchy, facetassocs)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
source code
 
__repr__(self)
repr(x)
source code
 
get_hit(self, index)
Get the hit with a given index.
source code
 
__getitem__(self, index)
Get the hit with a given index.
source code
 
__iter__(self)
Get an iterator over the hits in the search result.
source code
 
__len__(self)
Get the number of hits in the search result.
source code
 
get_top_tags(self, field, maxtags)
Get the most frequent tags in a given field.
source code
 
get_suggested_facets(self, maxfacets=5, desired_num_of_categories=7, required_facets=None)
Get a suggested set of facets, to present to the user.
source code

Inherited from object: __delattr__, __getattribute__, __hash__, __new__, __reduce__, __reduce_ex__, __setattr__, __str__

Properties
  more_matches
Check whether there are further matches after those in this result set.
  startrank
Get the rank of the first item in the search results.
  endrank
Get the rank of the item after the end of the search results.
  matches_lower_bound
Get a lower bound on the total number of matching documents.
  matches_upper_bound
Get an upper bound on the total number of matching documents.
  matches_human_readable_estimate
Get a human readable estimate of the number of matching documents.
  matches_estimated
Get an estimate for the total number of matching documents.
  estimate_is_exact
Check whether the estimated number of matching documents is exact.

Inherited from object: __class__

Method Details

__init__(self, conn, enq, query, mset, fieldmappings, tagspy, tagfields, facetspy, facetfields, facethierarchy, facetassocs)
(Constructor)

source code 
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
Overrides: object.__init__
(inherited documentation)

__repr__(self)
(Representation operator)

source code 
repr(x)
Overrides: object.__repr__
(inherited documentation)

__iter__(self)

source code 

Get an iterator over the hits in the search result.

The iterator returns the results in increasing order of rank.

__len__(self)
(Length operator)

source code 

Get the number of hits in the search result.

Note that this is not (usually) the number of matching documents for the search. If startrank is non-zero, it's not even the rank of the last document in the search result. It's simply the number of hits stored in the search result.

It is, however, the number of items returned by the iterator produced by calling iter() on this SearchResults object.

get_top_tags(self, field, maxtags)

source code 

Get the most frequent tags in a given field.

  • field - the field to get tags for. This must have been specified in the "gettags" argument of the search() call.
  • maxtags - the maximum number of tags to return.

Returns a sequence of 2-item tuples, in which the first item in the tuple is the tag, and the second is the frequency of the tag in the matches seen (as an integer).

get_suggested_facets(self, maxfacets=5, desired_num_of_categories=7, required_facets=None)

source code 

Get a suggested set of facets, to present to the user.

This returns a list, in descending order of the usefulness of the facet, in which each item is a tuple holding:

  • fieldname of facet.

  • sequence of 2-tuples holding the suggested values or ranges for that field:

    For facets of type 'string', the first item in the 2-tuple will simply be the string supplied when the facet value was added to its document. For facets of type 'float', it will be a 2-tuple, holding floats giving the start and end of the suggested value range.

    The second item in the 2-tuple will be the frequency of the facet value or range in the result set.

If required_facets is not None, it must be a field name, or a sequence of field names. Any field names mentioned in required_facets will be returned if there are any facet values at all in the search results for that field. The facet will only be omitted if there are no facet values at all for the field.

The value of maxfacets will be respected as far as possible; the exception is that if there are too many fields listed in required_facets with at least one value in the search results, extra facets will be returned (ie, obeying the required_facets parameter is considered more important than the maxfacets parameter).

If facet_hierarchy was indicated when search() was called, and the query included facets, then only subfacets of those query facets and top-level facets will be included in the returned list. Furthermore top-level facets will only be returned if there are remaining places in the list after it has been filled with subfacets. Note that required_facets is still respected regardless of the facet hierarchy.

If a query type was specified when search() was called, and the query included facets, then facets with an association of Never to the query type are never returned, even if mentioned in required_facets. Facets with an association of Preferred are listed before others in the returned list.


Property Details

more_matches

Check whether there are further matches after those in this result set.
Get Method:
xappy.searchconnection.SearchResults._get_more_matches(self)

startrank

Get the rank of the first item in the search results.

This corresponds to the "startrank" parameter passed to the search() method.

Get Method:
xappy.searchconnection.SearchResults._get_startrank(self)

endrank

Get the rank of the item after the end of the search results.

If there are sufficient results in the index, this corresponds to the "endrank" parameter passed to the search() method.

Get Method:
xappy.searchconnection.SearchResults._get_endrank(self)

matches_lower_bound

Get a lower bound on the total number of matching documents.
Get Method:
xappy.searchconnection.SearchResults._get_lower_bound(self)

matches_upper_bound

Get an upper bound on the total number of matching documents.
Get Method:
xappy.searchconnection.SearchResults._get_upper_bound(self)

matches_human_readable_estimate

Get a human readable estimate of the number of matching documents.

This consists of the value returned by the "matches_estimated" property, rounded to an appropriate number of significant digits (as determined by the values of the "matches_lower_bound" and "matches_upper_bound" properties).

Get Method:
xappy.searchconnection.SearchResults._get_human_readable_estimate(self)

matches_estimated

Get an estimate for the total number of matching documents.
Get Method:
xappy.searchconnection.SearchResults._get_estimated(self)

estimate_is_exact

Check whether the estimated number of matching documents is exact.

If this returns true, the estimate given by the matches_estimated property is guaranteed to be correct.

If this returns false, it is possible that the actual number of matching documents is different from the number given by the matches_estimated property.

Get Method:
xappy.searchconnection.SearchResults._estimate_is_exact(self)

xappy-0.5/docs/introduction.html0000644000175000017500000013476611005555237016714 0ustar richardrichard

Introduction

The "xappy" module is an easy-to-use interface to the Xapian search engine. Xapian provides a low level interface, dealing with terms and documents, but not really worrying about where terms come from, or how to build searches to match the way in which data has been indexed. In contrast, Xappy allows you to design a field structure, specifying what kind of information is held in particular fields, and then uses this field structure to index data appropriately, and to build and perform searches.

Installing and testing

Dependencies

You will need an up-to-date version of Xapian (both the core library and the corresponding Python bindings) to use Xappy. Unfortunately, the latest release (1.0.3) doesn't support all the features needed by Xappy, so you will either need a recent snapshot release, or to build from Xapian SVN HEAD. We recommend using a snapshot unless you are actively developing Xapian itself.

We hope that release 1.0.4 will be suitable for use with Xappy.

Installation

There is not yet a distutils setup script for xappy, but other than Xapian it has no dependencies or resources which need installing, so it may be installed simply by copying the "xappy" directory to somewhere on your Python path.

Once Xapian and Xappy are installed, you should be able to start the python interpreter and run:

>>> import xappy

Running the testsuite

To run the testsuite, simply run "./testsuite/runtests.py". This will display any errors produced when running the testsuite, and then display a coverage report for the modules tested.

The testsuite is composed of tests taken from three sources:

  • doctest tests in the code comments in the
  • additional doctest tests in text files with names of the form 'FOO_doctestN.txt', which test the module named "FOO" (and are run in a context in which the modules public symbols have all been imported).
  • additional documentation files (such as this one) which contain doctest formatted examples.

The list of core modules to test, and additional documentation files to check, is maintained in the "testsuite/runtests.py" file.

The coverage report displayed after running the testsuite is statement based, which is sadly one of the least precise methods of generating a coverage report, and counts lines as having been executed even if they haven't been tested in all possible code paths. On the plus side, its judgement is reliable if it considers that a line of code hasn't been tested. For this reason, it is reasonable to aim for 100% coverage by this metric, and the coverage report can be helpful to keep track of sections of code which aren't tested at all.

For any released version of Xappy, the coverage report should indicate 100% coverage for all modules. However, if you are using an SVN snapshot of Xappy, you may find that some code is not covered. In addition, the coverage testing currently contains a bug when run under Python 2.5 which causes some lines of code to be incorectly marked as "not covered" when they actually are. When run under Python 2.4, this bug doesn't manifest.

Building a database

Setting up a field structure

Before we process any documents, we need to create a database to hold the documents. This is done simply by creating an "IndexerConnection" object, and passing it the path we want to create the database at. If the database doesn't already exist, this will create a new, empty, database:

>>> conn = xappy.IndexerConnection('db1')

Note

All connections may only be accessed from a single thread at a time, and there may only be one IndexerConnection in existence at any given time. Additionally, it generally gives a large performance gain to ensure that the connection is kept open between modifications of the database, so that modifications can be grouped together. Therefore, you must protect access to the connection with a mutex if multiple threads might access it.

Once we've created an IndexerConnection, we can use it to specify the actions which should be performed on fields with a given name. There are several actions available, for different types of field content, and for different types of searches. You need to decide what actions you need before adding documents, because the database does not store enough information about documents to get back to the unprocessed document. The connection will allow you to change the field actions after documents have been added, but this change will not be reflected in any documents which have already been added to the database.

Fields which contain plain text should be added with the INDEX_FREETEXT action. This action takes various optional parameters:

  • weight: if this is supplied, the frequency information for all terms in the specified field will be multiplied by the given factor; this can be used for fields which are often a better indication of the subject matter than other fields (eg, title fields).
  • language: if this is supplied, it indicates the language that the supplied text is written in: this is used to perform language specific term normalising (to allow, for example, plural and singular forms to be matched). The language may be specified as a 2 character ISO-639 language code.
  • stop: if this is supplied, it must contain an sequence or other iterable which returns a list of stopwords, which will be filtered out of the index. This may reduce index size and improve search and indexing speed, but will reduce the flexibility of the search. Note that some information on the terms in the stoplist will still be stored, to allow phrase searches to be performed.
  • spell: this is a boolean flag; if supplied, and true, the contents of the field will be used for spelling correction.
  • nopos: this is a boolean flag; if supplied, and true, the positions of words in the field will not be stored. These are used for performing phrase and proximity searches, so this kind of search will not be possible on the field. On the other hand, the amount of data indexed for the field will be reduced, resulting in a lower database size, faster indexing, and potentially faster searching.
  • allow_field_specific: this is a boolean flag - if False, prevents terms with the field prefix being generated. This means that searches specific to this field will not work, and thus should only be used when only non-field specific searches are desired. Defaults to True.
  • search_by_default: this is a boolean flag - if False, the field will not be searched by non-field specific searches. If True, or omitted, the field will be included in searches for non field-specific searches.

All text passed to the interface is assumed to be UTF-8 encoded Unicode.

>>> conn.add_field_action('title', xappy.FieldActions.INDEX_FREETEXT, weight=5, language='en')
>>> conn.add_field_action('text', xappy.FieldActions.INDEX_FREETEXT, language='en', spell=True)

Any fields which contain exact values which we want to search for (such as a category name, or an ID number should be given the INDEX_EXACT actions. This doesn't perform any processing on the field value, so any symbols or punctuation will be preserved in the database:

>>> conn.add_field_action('category', xappy.FieldActions.INDEX_EXACT)

If we want to be able to sort on a field, we need to give it the SORTABLE action. By default, sorting is performed based on a lexicographical comparison of string values, but it is possible to set the sort order to be by date, or by floating point number. Fields which are given then SORTABLE action can also be used to restrict the results to a given range - think of it as declaring that there is a useful ordering for the field values.

Date values can be supplied as strings in the form YYYYMMDD or YYYY-MM-DD (or using / or . as separators). Floating point numbers can be in any representation which is understood by Python's float() function:

>>> conn.add_field_action('category', xappy.FieldActions.SORTABLE)
>>> conn.add_field_action('date', xappy.FieldActions.SORTABLE, type="date")
>>> conn.add_field_action('price', xappy.FieldActions.SORTABLE, type="float")

If we want to be able to be able to remove duplicates based on a field, we need to give it the COLLAPSE action. This allows the result set to be "collapsed" such that only the highest result with each value of a field will be returned. For example, we might want to just display the highest ranked document in each category (with a link to a list of the results in that category):

>>> conn.add_field_action('category', xappy.FieldActions.COLLAPSE)

If we want to be able to retrieve data from the document when it is the result of a search, we need to set the STORE_CONTENT action:

>>> conn.add_field_action('text', xappy.FieldActions.STORE_CONTENT)
>>> conn.add_field_action('title', xappy.FieldActions.STORE_CONTENT)
>>> conn.add_field_action('category', xappy.FieldActions.STORE_CONTENT)

If we want to use the contents of a field as "tags", which can be counted at search time (possibly, in order to build a tag-cloud, or other such visualisation), we need to set the TAG action:

>>> conn.add_field_action('tag', xappy.FieldActions.TAG)

Xappy also supports "faceted browsing": this means attaching "facets" to documents, where a facet is a value representing one aspect of information about a document: for example, the price of an object would be a facet of a document representing that object. Xappy supports storing many facets about a document, restricting the search results to only those documents which contain a particular facet, and automatically selecting a set of facets which are relevant to the set of results returned by a search (so that the facets can be presented to the user to be used to refine their search).

If we want to use a field as a facet, we simply add the FACET action to it. Facets can be of two types - "string" (which are just exact string matches), or "float" (which will automatically be grouped into ranges when returning a suggested list of facets). The default is "string":

>>> conn.add_field_action('price', xappy.FieldActions.FACET, type='float')
>>> conn.add_field_action('category', xappy.FieldActions.FACET, type='string')

Indexing

To add data to the database, we first create UnprocessedDocument objects. These contain a list of fields, which are processed in turn to create a ProcessedDocument, which can be added to the database. The ProcessedDocument can't be converted back into an UnprocessedDocument because some information is generally lost in this processing process (but it is possible to make alterations directly to the ProcessedDocument later.

We can access the list of fields in an UnprocessedDocument directly, using the fields member:

>>> doc = xappy.UnprocessedDocument()
>>> doc.fields.append(xappy.Field("title", "Our first document"))
>>> doc.fields.append(xappy.Field("text", "This is a paragraph of text.  It's quite short."))
>>> doc.fields.append(xappy.Field("text", "We can create another paragraph of text.  "
...                               "We can have as many of these as we like."))
>>> doc.fields.append(xappy.Field("category", "Test documents"))
>>> doc.fields.append(xappy.Field("tag", "Tag1"))
>>> doc.fields.append(xappy.Field("tag", "Test document"))
>>> doc.fields.append(xappy.Field("tag", "Test document"))
>>> doc.fields.append(xappy.Field("price", "20.56"))

We can add the document directly to the database: if we do this, the connection will process the document to generate a ProcessedDocument behind the scenes, and then add this:

>>> conn.add(doc)
'0'

Note that the add method returned a value '0'. This is a unique identifier for the document which was added, and may be used later to delete or replace the document. If we have externally generated unique identifiers, we can specify that the system should use them instead of generating its own, by setting the id property on the processed or unprocessed document before adding it to the database.

We can also ask the database to process a document explicitly before calling the "add" method. We might do this if we want to change the processed document in some way, but this isn't generally necessary:

>>> doc = xappy.UnprocessedDocument()
>>> doc.fields.append(xappy.Field("title", "Our second document"))
>>> doc.fields.append(xappy.Field("text", "In the beginning God created the heaven and the earth."))
>>> doc.fields.append(xappy.Field("category", "Bible"))
>>> doc.fields.append(xappy.Field("price", "12.20"))
>>> doc.id='Bible1'
>>> pdoc = conn.process(doc)
>>> conn.add(pdoc)
'Bible1'
>>> doc = xappy.UnprocessedDocument()
>>> doc.fields.append(xappy.Field("title", "Our third document"))
>>> doc.fields.append(xappy.Field("text", "And the earth was without form, and void; "
...                               "and darkness was upon the face of the deep. "
...                               "And the Spirit of God moved upon the face of the waters."))
>>> doc.fields.append(xappy.Field("category", "Bible"))
>>> doc.fields.append(xappy.Field("date", "17501225"))
>>> doc.fields.append(xappy.Field("price", "16.56"))
>>> doc.id='Bible2'
>>> pdoc = conn.process(doc)
>>> conn.add(pdoc)
'Bible2'

Once we have finished indexing, we should flush the changes to disk. Any changes which are unflushed may not be preserved if the processes exits without closing the database nicely:

>>> conn.flush()

Finally, we should close the connection to release its resources (if we leave this to the garbage collector, this might not happen for a long time). After closing, no other methods may be called on the connection, but a new connection can be made.:

>>> conn.close()

Searching

A search connection is opened similarly to an indexing connection. However, note that multiple search connections may be opened at once (though each connection must not be accessed from more than one thread). Search connections can even be open while indexing connections are:

>>> conn = xappy.SearchConnection('db1')

A search connection attempts to provide a stable view of the database, so when an update is made by a concurrent indexing process, the search connection will not reflect this change. This allows the results of the search to be gathered without needing to worry about concurrent updates (but see the section below about this for limitations on this facility).

The search connection can be reopened at any time to make it point to the latest version of the database:

>>> conn.reopen()

To perform a search, we need to specify what we're searching for. This is called a "Query", and the search connection provides several methods for building up a query. The simplest of these is the query_field method, which builds a query to search a single field:

>>> q = conn.query_field('text', 'create a paragraph')
>>> str(q)
'Xapian::Query(((ZXBcreat:(pos=1) AND ZXBa:(pos=2) AND ZXBparagraph:(pos=3)) AND_MAYBE (XBcreate:(pos=1) AND XBa:(pos=2) AND XBparagraph:(pos=3))))'

As you can see, the str() function will display the underlying Xapian query which is generated by the search connection. This may look a little weird at first, but you can get a general idea of the shape of the query.

The default operator for searches is "AND", but if we wish to be a little wider in our search, we can use the "OR" operator instead:

>>> q = conn.query_field('text', 'create a paragraph', default_op=conn.OP_OR)
>>> str(q)
'Xapian::Query(((ZXBcreat:(pos=1) OR ZXBa:(pos=2) OR ZXBparagraph:(pos=3)) AND_MAYBE (XBcreate:(pos=1) OR XBa:(pos=2) OR XBparagraph:(pos=3))))'

Once we have a query, we can use it to get a set of search results. Xapian is optimised for situations where only a small subset of the total result set is required, so when we perform a search we specify the starting rank (ie, the position in the total set of results, starting at 0) of the results we want to retrieve, and also the ending rank. Following usual Python conventions, the ending rank isn't inclusive, but the starting rank is.

In this case we want the first 10 results, so we can search with:

>>> results = conn.search(q, 0, 10)

The result set has a variety of pieces of information, but a useful one is the estimate of the total number of matching documents:

>>> results.matches_estimated
2

Only an estimated value is available because of Xapian's optimisations: the search process can often stop early because it has proved that there can be no better ranked documents, and especially for large searches, it would be a waste of time to then attempt to calculate the precise number of matching documents. We can check if the estimate is known to be correct by looking at the estimate_is_exact property:

>>> results.estimate_is_exact
True

The SearchResults object also provides upper and lower bounds on the number of matching documents, and a check for whether there are more results following those in this result set (very useful when writing a "pager" type interface, which needs to know whether to include a "Next" button).

Once you have a SearchResults object, you want to be able to get at the actual resulting documents. This can be done by using the get_hit() method, or by iterating through all the results with the usual Python iterator idiom. Both of these will return SearchResult objects, which is a subclass of ProcessedDocument, but has the additional property of rank:

>>> for result in results:
...     print result.rank, result.id, result.data['category']
0 0 ['Test documents']
1 Bible1 ['Bible']

In addition, SearchResults objects have methods allowing a highlighted or summarised version of a field to be displayed:

>>> results.get_hit(0).highlight('text')[0]
"This is <b>a</b> <b>paragraph</b> of text.  It's quite short."
>>> results.get_hit(0).summarise('text', maxlen=20)
'This is <b>a</b> <b>paragraph</b>..'

(Note that the highlight() method returns a list of field instances, as stored in the document data, so we've asked for it to only return the first of these, but the summarise() method joins these all together before generating the summary.)

Queries can be built and combined with other methods. The most flexible of these is the query_parse() method, which allows a user entered query to be parsed appropriately. The parser understands "Google style" searches, in which a search term can be restricted to a specified field by writing "fieldname:term", and in which boolean operators can be used in the search. The full syntax is described in the Xapian QueryParser documentation. (Note that the wildcard option is currently disabled by default.)

If a field has been indexed with the "spell" option turned on, the spell_correct() method can return a version of the query string with the spelling corrected. This method takes similar arguments to query_parse(), but instead of performing a search, it returns the corrected query string (or the original query string, if no spelling corrections were found).

>>> conn.spell_correct('teext')
'text'

In addition, two queries may be combined (with an AND or OR operator) using the query_composite() method, or a query can be "filtered" with another query such that only documents which match both queries will be returned (but the rankings are determined by the first query) using the query_filter() method.

To perform a range restriction, a range query can be built using the query_range() method. This will return a query which matches all documents in the database which satisfy the range restriction:

>>> rq = conn.query_range('date', '20000101', '20010101')

This query can be performed on its own, but note that for a large database it could take a long time to run, because if run on its own it will iterate through all the values in the database to return those which fit in the range. Instead, it will usually be used in conjunction with the query_filter() method, to filter the results of an existing query:

>>> filtered_query = conn.query_filter(q, rq)
>>> print filtered_query
Xapian::Query((((ZXBcreat:(pos=1) OR ZXBa:(pos=2) OR ZXBparagraph:(pos=3)) AND_MAYBE (XBcreate:(pos=1) OR XBa:(pos=2) OR XBparagraph:(pos=3))) FILTER VALUE_RANGE 1 20000101 20010101))

Note

The implementation of sorting and range filtering for floating point values uses terms which typically contain non-printable characters. Don't panic if you call print on a query generated with query_range() and odd control-characters are displayed; it's probably normal.)

To get a list of the tags which are contained in the result set, we have to specify the gettags parameter to the search() method:

>>> results = conn.search(q, 0, 10, gettags='tag')
>>> results.get_top_tags('tag', 10)
[('tag1', 1), ('test document', 1)]

Note

When the result set is being generated, various optimisations are performed to avoid wasting time looking at documents which can't possibly get into the portion of the result set which has been requested. These are normally desirable optimisations because they can speed up searches considerably, but if information about the tags in the result set as a whole is desired, the optimisations can cause inaccurate values to be returned. Therefore, it is possible to force the search engine to look at at least a minimum number of results, by setting the "checkatleast" parameter of the search() method. As a special case, a value of -1 forces all matches to be examined, regardless of database size: this should be used with care, because it can result in slow searches.

To search for only those documents containing a given tag, we can use the query_field() method:

>>> results = conn.search(conn.query_field('tag', 'tag1'), 0, 10)
>>> results.matches_estimated, results.estimate_is_exact
(1, True)
>>> results.get_hit(0).highlight('text')[0]
"This is a paragraph of text.  It's quite short."

To get a list of facets which are relevant to the result set, we have to specify the getfacets parameter to the search() method. We can also specify the allowfacets or denyfacets parameters to control the set of facets which are considered for display (this may be useful to reduce work if we've already restricted to a particular facet value, for example). Note that as with the gettags option, it may be advisable to specify a reasonably high value for the "checkatleast" parameter:

>>> results = conn.search(q, 0, 10, checkatleast=1000, getfacets=True)
>>> results.get_suggested_facets()
[('category', [('bible', 1), ('test documents', 1)]), ('price', [((12.199999999999999, 12.199999999999999), 1), ((20.559999999999999, 20.559999999999999), 1)])]

Note that the values for the suggested facets contain the string for facets of type "string", but contain a pair of numbers for facets of type "float" - these numbers define an automatically suggested range of values to use for the facet.

To restrict a further search to a particular value of the facet, or range of facets, a query can be produced using the query_facet() method. This will often be combined with an existing query using query_filter(), but you are free to use it differently if you wish. Note that the values in the output of get_suggested_facets() are in a form suitable for passing to the value parameter of query_facet(). For example, results can be restricted using a "string" facet like this:

>>> facet_q = conn.query_facet('category', 'bible')
>>> results = conn.search(conn.query_filter(q, facet_q), 0, 10)
>>> for result in results:
...     print result.rank, result.id, result.data['category']
0 Bible1 ['Bible']

Or can be restricted using a "float" facet like this:

>>> facet_q = conn.query_facet('price', (20.559999999999999, 20.559999999999999))
>>> results = conn.search(conn.query_filter(q, facet_q), 0, 10)
>>> for result in results:
...     print result.rank, result.id, result.data['category']
0 0 ['Test documents']

Finding similar documents

Sometimes, instead of searching for documents matching a specific set of criteria, you want to find documents similar to a document (or documents) that you already have. You might also want to combine such a similarity search with a search for some specific criteria; restricting the results by the criteria, but sorting in similarity order.

This can be achieved using the query_similar() method, which produces a query, based on a list of document ids, which will return documents similar to those identified by the supplied document IDs.

The similarity search is only based on the terms generated for free text searching (ie, with the INDEX_FREETEXT action), so there must be at least one such field for the similarity search to work. By default, all fields indexed with INDEX_FREETEXT will be used for the similarity search, but the list of fields to use may be controlled with the allow and deny parameters.

In addition, the number of terms to use for the similarity calculation may be controlled with the simterms parameter (which defaults to 10). A higher value will allow documents which are less similar to appear in the result set (but the most similar documents will still occur first). A lower value will usually result in a faster search. 10 is probably a suitable value in most situations, but experimentation may be worthwhile for a particular dataset to determine whether changing the value can improve the results (or produce a useful speedup without compromising the results).

To perform a simple similarity search, based on a few document IDs:

>>> simq = conn.query_similar(('Bible1',))
>>> results = conn.search(simq, 0, 10)
>>> [result.id for result in results]
['Bible1', 'Bible2', '0']

Note that the document ID supplied came first in the set of results. While this is not guaranteed (in particular, it may not occur if there are other documents in the search corpus which are very similar to the supplied documents), this will usually be the case - if you wish to ignore the documents specified, you should ask for the appropriate number of extra results, and filter them out at display time (don't just ignore the top N results, assuming that they are those supplied).

To perform a normal search, but reorder the ranking based on similarity, use the query_filter() method to filter the results of a similarity search to be only those documents which match the normal search:

>>> plainq = conn.query_field('text', 'God OR moved OR text')
>>> simq = conn.query_similar(('Bible1',))
>>> combined = conn.query_filter(simq, plainq)

>>> results = conn.search(plainq, 0, 10)
>>> [result.id for result in results]
['Bible2', '0', 'Bible1']

>>> results = conn.search(combined, 0, 10)
>>> [result.id for result in results]
['Bible1', 'Bible2', '0']

Concurrent update limitations

Unfortunately, Xapian's current database implementation doesn't allow search connections to be arbitrarily old: once two updates have been made to the database since the connection was opened, the connection may fail with a "DatabaseModifiedError" when it tries to access the database. Once this has happened, the search connection needs to be reopened to proceed further, and will then access a new, updated, view of the database.

To make this easier to manage, if the "DatabaseModifiedError" occurs during the search process, the error will be handled automatically, and the search will be re-performed. However, it is still possible for the error to occur when retrieving the document data from a search result, so handling for this should be included in code which reads the data from search results.

To avoid this happening, avoid calling the flush() method on the indexer connection too frequently, and call the reopen() method on the search connection before performing each new search. You should generally try not to call flush() more than once every 60 seconds anyway, because performance with many small flushes will be sub-optimal.

We hope to remove this restriction in a future release of Xapian.

Sorting

By default, the results are returned in order sorted by their "relevance" to the query, with the most relevant documents returned first. This order may be changed by specifying the sortby parameter of the search() method. The field specified in this parameter must have been given the SORTABLE action before indexing:

>>> results = conn.search(q, 0, 10, sortby='category')
>>> for result in results:
...     print result.rank, result.id, result.data['category']
0 Bible1 ['Bible']
1 0 ['Test documents']

The sort is in ascending order by default (ie, documents with a field value which is first in order will be returned first). The opposite order can be requested by preceding the field name with a "-" sign:

>>> results = conn.search(q, 0, 10, sortby='-category')
>>> for result in results:
...     print result.rank, result.id, result.data['category']
0 0 ['Test documents']
1 Bible1 ['Bible']

Note

There is some potential for confusion here, because Xapian defines ascending order in the opposite direction: its logic is that ascending order means that the value should be highest in documents which come top of the result list. This seems counter-intuitive to many people, and hopefully the sort order definition here will seem more natural.

If the sort terms are equal, the documents with equal sort terms will be returned in relevance order.

Collapsing

Xapian offers the useful feature of collapsing the result set such that only the top result with a given "collapse" value is returned. This feature can be used by adding a COLLAPSE action to the field before indexing, and then setting the collapse parameter of the search() method to the field name:

>>> q = conn.query_field('title', 'document')
>>> [result.id for result in conn.search(q, 0, 10)]
['Bible1', '0', 'Bible2']
>>> [result.id for result in conn.search(q, 0, 10, collapse='category')]
['Bible1', '0']

Errors

Most errors raised by xappy will be a subclass of xappy.SearchEngineError (the only deliberate exceptions are standard python errors, caused by invalid parameters being supplied to xappy). Any errors related to searching will be instances of xappy.SearchError, and errors related to indexing will be instances of xappy.IndexerError.

Errors may also be raised by the underlying Xapian library. For example, if you attempt to make two simultaneous IndexerConnections to a single database, Xapian will raise a xapian.DatabaseLockError. However, to avoid users of xappy needing to import xapian, the xapian errors are exposed by xappy. For example, xapian.DatabaseLockError can be caught by catching xappy.XapianDatabaseLockError (note the "Xapian" prefix of "XapianDatabaseLockError"). In addition, the inheritance heirarchy of the xapian errors is modified so that xappy.XapianError can be used as a catch-all for all Xapian errors, and xappy.SearchEngineError will catch all Xapian errors as well as any errors directly from xappy.

Other documentation

Detailed API documentation is available as docstrings in the Python code, but you may find it more convenient to browse it in formatted form (as generated by epydoc).

xappy-0.5/docs/introduction.rst0000644000175000017500000007645511001744507016554 0ustar richardrichardIntroduction ============ .. contents:: Table of contents The "xappy" module is an easy-to-use interface to the Xapian search engine. Xapian provides a low level interface, dealing with terms and documents, but not really worrying about where terms come from, or how to build searches to match the way in which data has been indexed. In contrast, Xappy allows you to design a field structure, specifying what kind of information is held in particular fields, and then uses this field structure to index data appropriately, and to build and perform searches. Installing and testing ====================== Dependencies ------------ You will need an up-to-date version of Xapian (both the core library and the corresponding Python bindings) to use Xappy. Unfortunately, the latest release (1.0.3) doesn't support all the features needed by Xappy, so you will either need a recent snapshot release, or to build from Xapian SVN HEAD. We recommend using a snapshot unless you are actively developing Xapian itself. We hope that release 1.0.4 will be suitable for use with Xappy. Installation ------------ There is not yet a distutils setup script for xappy, but other than Xapian it has no dependencies or resources which need installing, so it may be installed simply by copying the "xappy" directory to somewhere on your Python path. Once Xapian and Xappy are installed, you should be able to start the python interpreter and run:: >>> import xappy Running the testsuite --------------------- To run the testsuite, simply run "./testsuite/runtests.py". This will display any errors produced when running the testsuite, and then display a coverage report for the modules tested. The testsuite is composed of tests taken from three sources: - doctest tests in the code comments in the - additional doctest tests in text files with names of the form 'FOO_doctestN.txt', which test the module named "FOO" (and are run in a context in which the modules public symbols have all been imported). - additional documentation files (such as this one) which contain doctest formatted examples. The list of core modules to test, and additional documentation files to check, is maintained in the "testsuite/runtests.py" file. The coverage report displayed after running the testsuite is statement based, which is sadly one of the least precise methods of generating a coverage report, and counts lines as having been executed even if they haven't been tested in all possible code paths. On the plus side, its judgement is reliable if it considers that a line of code hasn't been tested. For this reason, it is reasonable to aim for 100% coverage by this metric, and the coverage report can be helpful to keep track of sections of code which aren't tested at all. For any released version of Xappy, the coverage report should indicate 100% coverage for all modules. However, if you are using an SVN snapshot of Xappy, you may find that some code is not covered. In addition, the coverage testing currently contains a bug when run under Python 2.5 which causes some lines of code to be incorectly marked as "not covered" when they actually are. When run under Python 2.4, this bug doesn't manifest. Building a database =================== Setting up a field structure ---------------------------- Before we process any documents, we need to create a database to hold the documents. This is done simply by creating an "IndexerConnection" object, and passing it the path we want to create the database at. If the database doesn't already exist, this will create a new, empty, database:: >>> conn = xappy.IndexerConnection('db1') .. note:: All connections may only be accessed from a single thread at a time, and there may only be one IndexerConnection in existence at any given time. Additionally, it generally gives a large performance gain to ensure that the connection is kept open between modifications of the database, so that modifications can be grouped together. Therefore, you must protect access to the connection with a mutex if multiple threads might access it. Once we've created an IndexerConnection, we can use it to specify the actions which should be performed on fields with a given name. There are several actions available, for different types of field content, and for different types of searches. You need to decide what actions you need before adding documents, because the database does not store enough information about documents to get back to the unprocessed document. The connection will allow you to change the field actions after documents have been added, but this change will not be reflected in any documents which have already been added to the database. Fields which contain plain text should be added with the ``INDEX_FREETEXT`` action. This action takes various optional parameters: - ``weight``: if this is supplied, the frequency information for all terms in the specified field will be multiplied by the given factor; this can be used for fields which are often a better indication of the subject matter than other fields (eg, title fields). - ``language``: if this is supplied, it indicates the language that the supplied text is written in: this is used to perform language specific term normalising (to allow, for example, plural and singular forms to be matched). The language may be specified as a 2 character ISO-639 language code. - ``stop``: if this is supplied, it must contain an sequence or other iterable which returns a list of stopwords, which will be filtered out of the index. This may reduce index size and improve search and indexing speed, but will reduce the flexibility of the search. Note that some information on the terms in the stoplist will still be stored, to allow phrase searches to be performed. - ``spell``: this is a boolean flag; if supplied, and true, the contents of the field will be used for spelling correction. - ``nopos``: this is a boolean flag; if supplied, and true, the positions of words in the field will not be stored. These are used for performing phrase and proximity searches, so this kind of search will not be possible on the field. On the other hand, the amount of data indexed for the field will be reduced, resulting in a lower database size, faster indexing, and potentially faster searching. - ``allow_field_specific``: this is a boolean flag - if False, prevents terms with the field prefix being generated. This means that searches specific to this field will not work, and thus should only be used when only non-field specific searches are desired. Defaults to True. - ``search_by_default``: this is a boolean flag - if False, the field will not be searched by non-field specific searches. If True, or omitted, the field will be included in searches for non field-specific searches. All text passed to the interface is assumed to be UTF-8 encoded Unicode. :: >>> conn.add_field_action('title', xappy.FieldActions.INDEX_FREETEXT, weight=5, language='en') >>> conn.add_field_action('text', xappy.FieldActions.INDEX_FREETEXT, language='en', spell=True) Any fields which contain exact values which we want to search for (such as a category name, or an ID number should be given the ``INDEX_EXACT`` actions. This doesn't perform any processing on the field value, so any symbols or punctuation will be preserved in the database:: >>> conn.add_field_action('category', xappy.FieldActions.INDEX_EXACT) If we want to be able to sort on a field, we need to give it the ``SORTABLE`` action. By default, sorting is performed based on a lexicographical comparison of string values, but it is possible to set the sort order to be by date, or by floating point number. Fields which are given then ``SORTABLE`` action can also be used to restrict the results to a given range - think of it as declaring that there is a useful ordering for the field values. Date values can be supplied as strings in the form YYYYMMDD or YYYY-MM-DD (or using / or . as separators). Floating point numbers can be in any representation which is understood by Python's float() function:: >>> conn.add_field_action('category', xappy.FieldActions.SORTABLE) >>> conn.add_field_action('date', xappy.FieldActions.SORTABLE, type="date") >>> conn.add_field_action('price', xappy.FieldActions.SORTABLE, type="float") If we want to be able to be able to remove duplicates based on a field, we need to give it the ``COLLAPSE`` action. This allows the result set to be "collapsed" such that only the highest result with each value of a field will be returned. For example, we might want to just display the highest ranked document in each category (with a link to a list of the results in that category):: >>> conn.add_field_action('category', xappy.FieldActions.COLLAPSE) If we want to be able to retrieve data from the document when it is the result of a search, we need to set the ``STORE_CONTENT`` action:: >>> conn.add_field_action('text', xappy.FieldActions.STORE_CONTENT) >>> conn.add_field_action('title', xappy.FieldActions.STORE_CONTENT) >>> conn.add_field_action('category', xappy.FieldActions.STORE_CONTENT) If we want to use the contents of a field as "tags", which can be counted at search time (possibly, in order to build a tag-cloud, or other such visualisation), we need to set the ``TAG`` action:: >>> conn.add_field_action('tag', xappy.FieldActions.TAG) Xappy also supports "faceted browsing": this means attaching "facets" to documents, where a facet is a value representing one aspect of information about a document: for example, the price of an object would be a facet of a document representing that object. Xappy supports storing many facets about a document, restricting the search results to only those documents which contain a particular facet, and automatically selecting a set of facets which are relevant to the set of results returned by a search (so that the facets can be presented to the user to be used to refine their search). If we want to use a field as a facet, we simply add the ``FACET`` action to it. Facets can be of two types - "string" (which are just exact string matches), or "float" (which will automatically be grouped into ranges when returning a suggested list of facets). The default is "string":: >>> conn.add_field_action('price', xappy.FieldActions.FACET, type='float') >>> conn.add_field_action('category', xappy.FieldActions.FACET, type='string') Indexing -------- To add data to the database, we first create ``UnprocessedDocument`` objects. These contain a list of fields, which are processed in turn to create a ``ProcessedDocument``, which can be added to the database. The ``ProcessedDocument`` can't be converted back into an ``UnprocessedDocument`` because some information is generally lost in this processing process (but it is possible to make alterations directly to the ``ProcessedDocument`` later. We can access the list of fields in an ``UnprocessedDocument`` directly, using the ``fields`` member:: >>> doc = xappy.UnprocessedDocument() >>> doc.fields.append(xappy.Field("title", "Our first document")) >>> doc.fields.append(xappy.Field("text", "This is a paragraph of text. It's quite short.")) >>> doc.fields.append(xappy.Field("text", "We can create another paragraph of text. " ... "We can have as many of these as we like.")) >>> doc.fields.append(xappy.Field("category", "Test documents")) >>> doc.fields.append(xappy.Field("tag", "Tag1")) >>> doc.fields.append(xappy.Field("tag", "Test document")) >>> doc.fields.append(xappy.Field("tag", "Test document")) >>> doc.fields.append(xappy.Field("price", "20.56")) We can add the document directly to the database: if we do this, the connection will process the document to generate a ``ProcessedDocument`` behind the scenes, and then add this:: >>> conn.add(doc) '0' Note that the ``add`` method returned a value ``'0'``. This is a unique identifier for the document which was added, and may be used later to delete or replace the document. If we have externally generated unique identifiers, we can specify that the system should use them instead of generating its own, by setting the ``id`` property on the processed or unprocessed document before adding it to the database. We can also ask the database to process a document explicitly before calling the "add" method. We might do this if we want to change the processed document in some way, but this isn't generally necessary:: >>> doc = xappy.UnprocessedDocument() >>> doc.fields.append(xappy.Field("title", "Our second document")) >>> doc.fields.append(xappy.Field("text", "In the beginning God created the heaven and the earth.")) >>> doc.fields.append(xappy.Field("category", "Bible")) >>> doc.fields.append(xappy.Field("price", "12.20")) >>> doc.id='Bible1' >>> pdoc = conn.process(doc) >>> conn.add(pdoc) 'Bible1' >>> doc = xappy.UnprocessedDocument() >>> doc.fields.append(xappy.Field("title", "Our third document")) >>> doc.fields.append(xappy.Field("text", "And the earth was without form, and void; " ... "and darkness was upon the face of the deep. " ... "And the Spirit of God moved upon the face of the waters.")) >>> doc.fields.append(xappy.Field("category", "Bible")) >>> doc.fields.append(xappy.Field("date", "17501225")) >>> doc.fields.append(xappy.Field("price", "16.56")) >>> doc.id='Bible2' >>> pdoc = conn.process(doc) >>> conn.add(pdoc) 'Bible2' Once we have finished indexing, we should flush the changes to disk. Any changes which are unflushed may not be preserved if the processes exits without closing the database nicely:: >>> conn.flush() Finally, we should close the connection to release its resources (if we leave this to the garbage collector, this might not happen for a long time). After closing, no other methods may be called on the connection, but a new connection can be made.:: >>> conn.close() Searching ========= A search connection is opened similarly to an indexing connection. However, note that multiple search connections may be opened at once (though each connection must not be accessed from more than one thread). Search connections can even be open while indexing connections are:: >>> conn = xappy.SearchConnection('db1') A search connection attempts to provide a stable view of the database, so when an update is made by a concurrent indexing process, the search connection will not reflect this change. This allows the results of the search to be gathered without needing to worry about concurrent updates (but see the section below about this for limitations on this facility). The search connection can be reopened at any time to make it point to the latest version of the database:: >>> conn.reopen() To perform a search, we need to specify what we're searching for. This is called a "Query", and the search connection provides several methods for building up a query. The simplest of these is the ``query_field`` method, which builds a query to search a single field:: >>> q = conn.query_field('text', 'create a paragraph') >>> str(q) 'Xapian::Query(((ZXBcreat:(pos=1) AND ZXBa:(pos=2) AND ZXBparagraph:(pos=3)) AND_MAYBE (XBcreate:(pos=1) AND XBa:(pos=2) AND XBparagraph:(pos=3))))' As you can see, the str() function will display the underlying Xapian query which is generated by the search connection. This may look a little weird at first, but you can get a general idea of the shape of the query. The default operator for searches is "AND", but if we wish to be a little wider in our search, we can use the "OR" operator instead:: >>> q = conn.query_field('text', 'create a paragraph', default_op=conn.OP_OR) >>> str(q) 'Xapian::Query(((ZXBcreat:(pos=1) OR ZXBa:(pos=2) OR ZXBparagraph:(pos=3)) AND_MAYBE (XBcreate:(pos=1) OR XBa:(pos=2) OR XBparagraph:(pos=3))))' Once we have a query, we can use it to get a set of search results. Xapian is optimised for situations where only a small subset of the total result set is required, so when we perform a search we specify the starting `rank` (ie, the position in the total set of results, starting at 0) of the results we want to retrieve, and also the ending rank. Following usual Python conventions, the ending rank isn't inclusive, but the starting rank is. In this case we want the first 10 results, so we can search with:: >>> results = conn.search(q, 0, 10) The result set has a variety of pieces of information, but a useful one is the estimate of the total number of matching documents:: >>> results.matches_estimated 2 Only an estimated value is available because of Xapian's optimisations: the search process can often stop early because it has proved that there can be no better ranked documents, and especially for large searches, it would be a waste of time to then attempt to calculate the precise number of matching documents. We can check if the estimate is known to be correct by looking at the ``estimate_is_exact`` property:: >>> results.estimate_is_exact True The ``SearchResults`` object also provides upper and lower bounds on the number of matching documents, and a check for whether there are more results following those in this result set (very useful when writing a "pager" type interface, which needs to know whether to include a "Next" button). Once you have a ``SearchResults`` object, you want to be able to get at the actual resulting documents. This can be done by using the ``get_hit()`` method, or by iterating through all the results with the usual Python iterator idiom. Both of these will return ``SearchResult`` objects, which is a subclass of ``ProcessedDocument``, but has the additional property of `rank`:: >>> for result in results: ... print result.rank, result.id, result.data['category'] 0 0 ['Test documents'] 1 Bible1 ['Bible'] In addition, ``SearchResults`` objects have methods allowing a highlighted or summarised version of a field to be displayed:: >>> results.get_hit(0).highlight('text')[0] "This is a paragraph of text. It's quite short." >>> results.get_hit(0).summarise('text', maxlen=20) 'This is a paragraph..' (Note that the highlight() method returns a list of field instances, as stored in the document data, so we've asked for it to only return the first of these, but the summarise() method joins these all together before generating the summary.) Queries can be built and combined with other methods. The most flexible of these is the ``query_parse()`` method, which allows a user entered query to be parsed appropriately. The parser understands "Google style" searches, in which a search term can be restricted to a specified field by writing "fieldname:term", and in which boolean operators can be used in the search. The full syntax is described in the `Xapian QueryParser documentation`_. (Note that the wildcard option is currently disabled by default.) If a field has been indexed with the "spell" option turned on, the ``spell_correct()`` method can return a version of the query string with the spelling corrected. This method takes similar arguments to ``query_parse()``, but instead of performing a search, it returns the corrected query string (or the original query string, if no spelling corrections were found). >>> conn.spell_correct('teext') 'text' In addition, two queries may be combined (with an AND or OR operator) using the ``query_composite()`` method, or a query can be "filtered" with another query such that only documents which match both queries will be returned (but the rankings are determined by the first query) using the ``query_filter()`` method. To perform a range restriction, a range query can be built using the ``query_range()`` method. This will return a query which matches all documents in the database which satisfy the range restriction:: >>> rq = conn.query_range('date', '20000101', '20010101') This query can be performed on its own, but note that for a large database it could take a long time to run, because if run on its own it will iterate through all the values in the database to return those which fit in the range. Instead, it will usually be used in conjunction with the ``query_filter()`` method, to filter the results of an existing query:: >>> filtered_query = conn.query_filter(q, rq) >>> print filtered_query Xapian::Query((((ZXBcreat:(pos=1) OR ZXBa:(pos=2) OR ZXBparagraph:(pos=3)) AND_MAYBE (XBcreate:(pos=1) OR XBa:(pos=2) OR XBparagraph:(pos=3))) FILTER VALUE_RANGE 1 20000101 20010101)) .. Note:: The implementation of sorting and range filtering for floating point values uses terms which typically contain non-printable characters. Don't panic if you call ``print`` on a query generated with ``query_range()`` and odd control-characters are displayed; it's probably normal.) To get a list of the tags which are contained in the result set, we have to specify the gettags parameter to the search() method:: >>> results = conn.search(q, 0, 10, gettags='tag') >>> results.get_top_tags('tag', 10) [('tag1', 1), ('test document', 1)] .. Note:: When the result set is being generated, various optimisations are performed to avoid wasting time looking at documents which can't possibly get into the portion of the result set which has been requested. These are normally desirable optimisations because they can speed up searches considerably, but if information about the tags in the result set as a whole is desired, the optimisations can cause inaccurate values to be returned. Therefore, it is possible to force the search engine to look at at least a minimum number of results, by setting the "checkatleast" parameter of the search() method. As a special case, a value of -1 forces all matches to be examined, regardless of database size: this should be used with care, because it can result in slow searches. To search for only those documents containing a given tag, we can use the query_field() method:: >>> results = conn.search(conn.query_field('tag', 'tag1'), 0, 10) >>> results.matches_estimated, results.estimate_is_exact (1, True) >>> results.get_hit(0).highlight('text')[0] "This is a paragraph of text. It's quite short." To get a list of facets which are relevant to the result set, we have to specify the getfacets parameter to the search() method. We can also specify the allowfacets or denyfacets parameters to control the set of facets which are considered for display (this may be useful to reduce work if we've already restricted to a particular facet value, for example). Note that as with the gettags option, it may be advisable to specify a reasonably high value for the "checkatleast" parameter:: >>> results = conn.search(q, 0, 10, checkatleast=1000, getfacets=True) >>> results.get_suggested_facets() [('category', [('bible', 1), ('test documents', 1)]), ('price', [((12.199999999999999, 12.199999999999999), 1), ((20.559999999999999, 20.559999999999999), 1)])] Note that the values for the suggested facets contain the string for facets of type "string", but contain a pair of numbers for facets of type "float" - these numbers define an automatically suggested range of values to use for the facet. To restrict a further search to a particular value of the facet, or range of facets, a query can be produced using the query_facet() method. This will often be combined with an existing query using query_filter(), but you are free to use it differently if you wish. Note that the values in the output of get_suggested_facets() are in a form suitable for passing to the value parameter of query_facet(). For example, results can be restricted using a "string" facet like this:: >>> facet_q = conn.query_facet('category', 'bible') >>> results = conn.search(conn.query_filter(q, facet_q), 0, 10) >>> for result in results: ... print result.rank, result.id, result.data['category'] 0 Bible1 ['Bible'] Or can be restricted using a "float" facet like this:: >>> facet_q = conn.query_facet('price', (20.559999999999999, 20.559999999999999)) >>> results = conn.search(conn.query_filter(q, facet_q), 0, 10) >>> for result in results: ... print result.rank, result.id, result.data['category'] 0 0 ['Test documents'] Finding similar documents ------------------------- Sometimes, instead of searching for documents matching a specific set of criteria, you want to find documents similar to a document (or documents) that you already have. You might also want to combine such a similarity search with a search for some specific criteria; restricting the results by the criteria, but sorting in similarity order. This can be achieved using the ``query_similar()`` method, which produces a query, based on a list of document ids, which will return documents similar to those identified by the supplied document IDs. The similarity search is only based on the terms generated for free text searching (ie, with the ``INDEX_FREETEXT`` action), so there must be at least one such field for the similarity search to work. By default, all fields indexed with ``INDEX_FREETEXT`` will be used for the similarity search, but the list of fields to use may be controlled with the ``allow`` and ``deny`` parameters. In addition, the number of terms to use for the similarity calculation may be controlled with the ``simterms`` parameter (which defaults to 10). A higher value will allow documents which are less similar to appear in the result set (but the most similar documents will still occur first). A lower value will usually result in a faster search. 10 is probably a suitable value in most situations, but experimentation may be worthwhile for a particular dataset to determine whether changing the value can improve the results (or produce a useful speedup without compromising the results). To perform a simple similarity search, based on a few document IDs:: >>> simq = conn.query_similar(('Bible1',)) >>> results = conn.search(simq, 0, 10) >>> [result.id for result in results] ['Bible1', 'Bible2', '0'] Note that the document ID supplied came first in the set of results. While this is not guaranteed (in particular, it may not occur if there are other documents in the search corpus which are very similar to the supplied documents), this will usually be the case - if you wish to ignore the documents specified, you should ask for the appropriate number of extra results, and filter them out at display time (don't just ignore the top N results, assuming that they are those supplied). To perform a normal search, but reorder the ranking based on similarity, use the ``query_filter()`` method to filter the results of a similarity search to be only those documents which match the normal search:: >>> plainq = conn.query_field('text', 'God OR moved OR text') >>> simq = conn.query_similar(('Bible1',)) >>> combined = conn.query_filter(simq, plainq) >>> results = conn.search(plainq, 0, 10) >>> [result.id for result in results] ['Bible2', '0', 'Bible1'] >>> results = conn.search(combined, 0, 10) >>> [result.id for result in results] ['Bible1', 'Bible2', '0'] Concurrent update limitations ----------------------------- Unfortunately, Xapian's current database implementation doesn't allow search connections to be arbitrarily old: once *two* updates have been made to the database since the connection was opened, the connection may fail with a "DatabaseModifiedError" when it tries to access the database. Once this has happened, the search connection needs to be reopened to proceed further, and will then access a new, updated, view of the database. To make this easier to manage, if the "DatabaseModifiedError" occurs during the search process, the error will be handled automatically, and the search will be re-performed. However, it is still possible for the error to occur when retrieving the document data from a search result, so handling for this should be included in code which reads the data from search results. To avoid this happening, avoid calling the flush() method on the indexer connection too frequently, and call the reopen() method on the search connection before performing each new search. You should generally try not to call flush() more than once every 60 seconds anyway, because performance with many small flushes will be sub-optimal. We hope to remove this restriction in a future release of Xapian. Sorting ------- By default, the results are returned in order sorted by their "relevance" to the query, with the most relevant documents returned first. This order may be changed by specifying the sortby parameter of the search() method. The field specified in this parameter must have been given the ``SORTABLE`` action before indexing:: >>> results = conn.search(q, 0, 10, sortby='category') >>> for result in results: ... print result.rank, result.id, result.data['category'] 0 Bible1 ['Bible'] 1 0 ['Test documents'] The sort is in ascending order by default (ie, documents with a field value which is first in order will be returned first). The opposite order can be requested by preceding the field name with a "-" sign:: >>> results = conn.search(q, 0, 10, sortby='-category') >>> for result in results: ... print result.rank, result.id, result.data['category'] 0 0 ['Test documents'] 1 Bible1 ['Bible'] .. note:: There is some potential for confusion here, because Xapian defines ascending order in the opposite direction: its logic is that ascending order means that the value should be highest in documents which come top of the result list. This seems counter-intuitive to many people, and hopefully the sort order definition here will seem more natural. If the sort terms are equal, the documents with equal sort terms will be returned in relevance order. Collapsing ---------- Xapian offers the useful feature of collapsing the result set such that only the top result with a given "collapse" value is returned. This feature can be used by adding a ``COLLAPSE`` action to the field before indexing, and then setting the collapse parameter of the ``search()`` method to the field name:: >>> q = conn.query_field('title', 'document') >>> [result.id for result in conn.search(q, 0, 10)] ['Bible1', '0', 'Bible2'] >>> [result.id for result in conn.search(q, 0, 10, collapse='category')] ['Bible1', '0'] Errors ====== Most errors raised by xappy will be a subclass of xappy.SearchEngineError (the only deliberate exceptions are standard python errors, caused by invalid parameters being supplied to xappy). Any errors related to searching will be instances of xappy.SearchError, and errors related to indexing will be instances of xappy.IndexerError. Errors may also be raised by the underlying Xapian library. For example, if you attempt to make two simultaneous IndexerConnections to a single database, Xapian will raise a xapian.DatabaseLockError. However, to avoid users of xappy needing to import xapian, the xapian errors are exposed by xappy. For example, xapian.DatabaseLockError can be caught by catching xappy.XapianDatabaseLockError (note the "Xapian" prefix of "XapianDatabaseLockError"). In addition, the inheritance heirarchy of the xapian errors is modified so that xappy.XapianError can be used as a catch-all for all Xapian errors, and xappy.SearchEngineError will catch all Xapian errors as well as any errors directly from xappy. Other documentation =================== Detailed API documentation is available as docstrings in the Python code, but you may find it more convenient to browse it in `formatted form (as generated by epydoc)`_. .. _formatted form (as generated by epydoc): api/index.html .. _Xapian QueryParser documentation: http://xapian.org/docs/queryparser.html xappy-0.5/docs/running_perftest.txt0000644000175000017500000000201610702552751017421 0ustar richardrichardFirstly, check out xappy: svn co http://xappy.googlecode.com/svn/trunk xappy cd xappy/ Check it's working properly, if you like: python testsuite/runtests.py Now, go into the performance test directory: cd perftest/ mkdir sampledata The following instructions assume you're on atreus.tartarus.org. On other machines, you'll need to get the wikipedia data, and process it into a "scriptindex" dump format. This can be done using the "parse_wikipedia/wiki2dump.py" script inside the perftest directory (you can just ignore the "redirects output file"). Link to the wikipedia sample data: ln -s /home/richard/pub/data/wikipedia_processed/out_splitaa sampledata/wikipedia.dump (or use split_ab for a small piece of data) Generate some sample queries (the source data is in ../testdata - could do with better source data): python gen_queries.py mv ../testdata/queries.txt sampledata/ Finally, run the performance tests: python perftest.py The output will be placed in "perftestoutdir/" xappy-0.5/examples/0000755000175000017500000000000011005556727014157 5ustar richardrichardxappy-0.5/examples/fileindex.py0000755000175000017500000000504110667537053016507 0ustar richardrichard#!/usr/bin/env python import sys import os def _setup_path(): """Set up sys.path to allow us to import Xappy when run uninstalled. """ abspath = os.path.abspath(__file__) dirname = os.path.dirname(abspath) dirname, ourdir = os.path.split(dirname) dirname, parentdir = os.path.split(dirname) if (parentdir, ourdir) == ('xappy', 'examples'): sys.path.insert(0, '..') _setup_path() import xappy def create_index(dbpath): """Create a new index, and set up its field structure. """ iconn = xappy.IndexerConnection(dbpath) iconn.add_field_action('path', xappy.FieldActions.STORE_CONTENT) iconn.add_field_action('path', xappy.FieldActions.INDEX_EXACT) iconn.add_field_action('pathcomponent', xappy.FieldActions.INDEX_EXACT) iconn.add_field_action('text', xappy.FieldActions.STORE_CONTENT) iconn.add_field_action('text', xappy.FieldActions.INDEX_FREETEXT, language='en') iconn.close() def open_index(dbpath): """Open an existing index. """ return xappy.IndexerConnection(dbpath) def canonical_path(path): """Convert a path to a canonical form.""" path = os.path.realpath(path) path = os.path.normpath(path) path = os.path.normcase(path) return path def index_content(doc, filepath): """Index the content of the file.""" fd = open(filepath) contents = fd.read() fd.close() try: contents = unicode(contents) except UnicodeDecodeError: return doc.fields.append(xappy.Field('text', contents)) def index_file(iconn, filepath): """Index a file.""" filepath = canonical_path(filepath) doc = xappy.UnprocessedDocument() doc.fields.append(xappy.Field('path', filepath)) components = filepath while True: components, dirname = os.path.split(components) if len(dirname) == 0 or components == '/': break doc.fields.append(xappy.Field('pathcomponent', components)) index_content(doc, filepath) iconn.add(doc) return 1 def index_path(iconn, docpath): """Index a path.""" count = 0 for dirpath, dirnames, filenames in os.walk(docpath): for filename in filenames: filepath = os.path.join(dirpath, filename) index_file(iconn, filepath) count += 1 return count def main(argv): dbpath = 'foo' docpath = '/usr/share/doc/python2.5' create_index(dbpath) iconn = open_index(dbpath) count = index_path(iconn, docpath) print "Indexed %d documents." % count if __name__ == '__main__': main(sys.argv) xappy-0.5/examples/search.py0000755000175000017500000000252510667537061016010 0ustar richardrichard#!/usr/bin/env python import sys import os import re def _setup_path(): """Set up sys.path to allow us to import Xappy when run uninstalled. """ abspath = os.path.abspath(__file__) dirname = os.path.dirname(abspath) dirname, ourdir = os.path.split(dirname) dirname, parentdir = os.path.split(dirname) if (parentdir, ourdir) == ('xappy', 'examples'): sys.path.insert(0, '..') _setup_path() import xappy _whitespace_re = re.compile('\s+') def open_index(dbpath): return xappy.SearchConnection(dbpath) def main(argv): dbpath = 'foo' search = ' '.join(argv[1:]) sconn = open_index(dbpath) print "Searching %d documents for \"%s\"" % ( sconn.get_doccount(), search ) q = sconn.query_parse(search, default_op=sconn.OP_AND) results = sconn.search(q, 0, 10) if results.estimate_is_exact: print "Found %d results" % results.matches_estimated else: print "Found approximately %d results" % results.matches_estimated for result in results: print result.data['path'][0] try: summary = result.summarise('text', hl=('*', '*'), maxlen=300) summary = ' '.join(_whitespace_re.split(summary)) print summary except KeyError: pass print if __name__ == '__main__': main(sys.argv) xappy-0.5/libs/0000755000175000017500000000000011005556727013272 5ustar richardrichardxappy-0.5/libs/get_xapian.py0000755000175000017500000001461711005551573015771 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""get_xapian.py: Download and unpack the xapian archives. """ __docformat__ = "restructuredtext en" import copy import glob import os import sha import shutil import subprocess import sys import tarfile import tempfile import urllib2 # List of the archives. # # The values are, in order: # - Descriptive name of archive # - URL to download # - Filename to store downloaded package as # - SHA1 sum of package archives = ( ('Xapian core', 'http://xappy.googlecode.com/files/xapian-core-10411.tgz', 'xapian-core.tgz', '8cb209a20492dcb825aad26bae9da52e42e50e3d', '', ), ('Xapian bindings', 'http://xappy.googlecode.com/files/xapian-bindings-10411.tgz', 'xapian-bindings.tgz', '795c45683624e8e1691591c1b36a15215a41b1ad', '', ), ('Xapian win32 build system', 'http://xappy.googlecode.com/files/win32msvc-10411.tgz', 'win32msvc.tgz', 'f48b542ca5f3896923f8a0e1e677d15de417f5a2', 'xapian-core/win32', ), ) def get_script_dir(): """Get the path of the directory containing this script. """ global scriptdir if 'scriptdir' not in globals(): scriptdir = os.path.dirname(os.path.abspath(__file__)) return scriptdir def get_package_dir(): """Get the path to store the downloaded packages in. This is a standard location relative to this script. """ return os.path.abspath(os.path.join(get_script_dir(), '..', 'libs')) def calc_sha_hash(filepath): """Calculate the SHA1 hash of the file at the given path. """ hasher = sha.new() fd = open(filepath, 'rb', 0) try: while True: chunk = fd.read(65536) if len(chunk) == 0: break hasher.update(chunk) finally: fd.close() return hasher.hexdigest() def download_file(url, destpath): """Download a file, and place it in destpath. """ destdir = os.path.dirname(destpath) if not os.path.isdir(destdir): os.makedirs(destdir) fd = urllib2.urlopen(url) tmpfd, tmpname = tempfile.mkstemp(dir=destdir, prefix='xappy') try: os.write(tmpfd, fd.read()) os.close(tmpfd) os.rename(tmpname, destpath) finally: if os.path.exists(tmpname): os.unlink(tmpname) def unpack_tar_archive(filename, tempdir): """Unpack the tar archive at filename. Puts the contents in a directory with basename tempdir. """ tf = tarfile.open(filename) try: dirname = None for member in tf.getmembers(): topdir = member.name.split('/', 1)[0] if dirname is None: dirname = topdir else: if dirname != topdir: raise ValueError('Archive has multiple toplevel directories: %s and %s' % (topdir, dirname)) tf.extract(member, path=tempdir) return os.path.join(tempdir, dirname) finally: tf.close() def get_archive_from_url(name, url, archivename, expected_hash): """Download an archive from the specified URL. Returns the path the archive was downloaded to, or None if the archive couldn't be downloaded """ print("Checking for %s" % name) # Get the path that the package should be downloaded to filepath = os.path.join(package_dir, archivename) # Check if the package is already downloaded (and has correct SHA key). if os.path.exists(filepath): calculated_hash = calc_sha_hash(filepath) if expected_hash != calculated_hash: print("Package of %s at '%s' has wrong hash - discarding" % (name, archivename)) print("(Got %s, expected %s)" % (calculated_hash, expected_hash)) os.unlink(filepath) # Download the package if needed. if not os.path.exists(filepath): print("Downloading %s from %s" % (name, url)) download_file(url, filepath) calculated_hash = calc_sha_hash(filepath) if expected_hash != calculated_hash: print("Package of %s at '%s' has wrong hash - cannot continue" % (name, archivename)) print("(Got %s, expected %s)" % (calculated_hash, expected_hash)) os.unlink(filepath) return None return filepath def get_archives(archives): """Download and unpack the xapian archives. """ package_dir = get_package_dir() for name, url, archivename, expected_hash, target_location in archives: archivepath = get_archive_from_url(name, url, archivename, expected_hash) if archivepath is None: return False print("Unpacking %s" % name) archivedir = unpack_tar_archive(archivepath, package_dir) if target_location != '': target_path = os.path.join(package_dir, target_location) if os.path.exists(target_path): print("Removing old unpacked copy of archive from %s" % target_location) shutil.rmtree(target_path) print("Moving %s to %s" % (name, target_location)) shutil.move(archivedir, target_path) return True def make_file_writable(filename): if os.name == 'nt': import win32api, win32con x = win32api.GetFileAttributes(filename) x &= ~win32con.FILE_ATTRIBUTE_READONLY win32api.SetFileAttributes(filename, x) else: os.chmod(filename, 700) def make_tree_writable(root): for dirpath, dirnames, filenames in os.walk(root): for filename in filenames: filepath = os.path.join(dirpath, filename) make_file_writable(filepath) if __name__ == '__main__': package_dir = get_package_dir() if not get_archives(archives): sys.exit(1) sys.exit(0) xappy-0.5/perftest/0000755000175000017500000000000011005556727014175 5ustar richardrichardxappy-0.5/perftest/parse_wikipedia/0000755000175000017500000000000011005556727017335 5ustar richardrichardxappy-0.5/perftest/parse_wikipedia/Errors.py0000644000175000017500000000361710667526240021172 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2006 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import HTMLUtils class UserError(Exception): """ Class used to pass a minor error from code performing an action to code which displays errors to the user. The message stored in such an exception should be raw HTML, as passed to the browser. Any content in this message resulting from user inputs, MUST be HTML encoded (probably using HTMLUtils.encodeText()) to avoid risk of cross-site scripting attacks. For convenience, extra arguments may be provided which will be encoded and then merged with the message using the % operator. For example: >>> print UserError('Error message') Error message >>> print UserError('Error %s', 'message with quoted') Error message with <html> quoted """ _cname = 'UserError' def __init__(self, msg, *args): self.msg = msg % tuple(HTMLUtils.encodeText(arg) for arg in args) def __str__(self): return self.msg def __repr__(self): return '%s("%s")' % (self._cname, self.msg.replace('\\', '\\\\').replace('"', '\\"')) if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/perftest/parse_wikipedia/HTMLUtils.py0000644000175000017500000002030710667526240021476 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2006 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import urllib import re import htmlentitydefs def __booltonum(val): """Convert any boolean values to '0' or '1'. Leave other values alone. """ if val is True: return '1' elif val is False: return '0' return val def encodeParams(paramdict, **kwargs): """Encode a dictionary of parameters to a querystring. `paramdict` is a dictionary of parameters to encode. `kwargs` is an optional set of keyword arguments to be added to the parameters to be encoded. Any entries in kwargs which are also present in paramdict override the entries in paramdict. Any entries in kwargs with a value of None cause any corresponding entry in paramdict to be omitted from the encoded output. """ if isinstance(paramdict, dict): paramlist = [(key, __booltonum(val)) for (key, val) in paramdict.iteritems() if key not in kwargs and val is not None] else: paramlist = [(key, __booltonum(val)) for (key, val) in paramdict if key not in kwargs and val is not None] paramlist.extend([(key, val) for (key, val) in kwargs.iteritems() if val is not None]) paramlist.sort() return urllib.urlencode (paramlist) def encodeAttribValue(value): """ Encode an attribute value by replacing HTML characters with entity values. The value may be unicode or a UTF-8 encoded string. The result is a UTF-8 encoded string. >>> encodeAttribValue('bar') 'bar' >>> encodeAttribValue('bar"') 'bar"' >>> encodeAttribValue('bar"<>&"') 'bar"<>&"' >>> print repr(encodeAttribValue(u'bar\\xa3')) 'bar£' >>> utf8=u'bar\\xa3\\u1234'.encode('utf-8') >>> print repr(utf8) 'bar\\xc2\\xa3\\xe1\\x88\\xb4' >>> print repr(encodeAttribValue(utf8)) 'bar£ሴ' Ampersands are escaped even if they already form part of a valid entity: >>> encodeAttribValue('bar"<>&"') 'bar&quot;<>&"' All non-alphanumeric characters are also escaped. """ result = [] if isinstance(value, str): value = unicode(value, 'utf-8') for char in value: if (char >= '0' and char <= '9') or (char >= 'a' and char <= 'z') or (char >= 'A' and char <= 'Z') or char in './#_': result.append(char) elif char == '&': result.append('&') elif char == '"': result.append('"') elif char == '<': result.append('<') elif char == '>': result.append('>') elif char == '(': result.append('(') elif char == ')': result.append(')') elif char == '#': result.append('#') else: result.append('&#%s;' % hex(ord(char))[1:]) return ''.join(result).encode('utf-8') def encodeText(value): """Encode a piece of text by replacing HTML characters with entity values. >>> encodeText('bar') 'bar' >>> encodeText('bar"') 'bar"' >>> encodeText('bar"<>&"(') 'bar"<>&"(' Ampersands are escaped even if they already form part of a valid entity: >>> encodeText('bar"<>&"') 'bar&quot;<>&"' A non-string will be returned unchanged: >>> encodeText(1) 1 """ if not isinstance(value, basestring): return value result = value.replace('&', '&') result = result.replace('#', '#') result = result.replace('"', '"') result = result.replace('<', '<') result = result.replace('>', '>') return result def percentEncode(value): """Percent encode a component of a URI. This replaces special characters with %XX where XX is the hexadecimal value of the character. Currently replaces all non-alphanumeric characters with the following exceptions: is replaced by + ., /, #, _, = are not replaced. >>> percentEncode('q=M&%&%; S') 'q=M%26%25%26%25%3B+S' >>> percentEncode(u'\u00a3') '%C2%A3' """ result = [] if isinstance(value, unicode): value = value.encode('utf-8') assert isinstance(value, str) for char in value: if (char >= '0' and char <= '9') or (char >= 'a' and char <= 'z') or (char >= 'A' and char <= 'Z') or char in './#_=': result.append(char) elif char == ' ': result.append('+') else: result.append('%%%s' % hex(ord(char)).upper()[2:]) return ''.join(result) def percentDecode(value): r"""Percent decode a component or a URI. This replaces percent encode sequences (ie, %XX, where XX is the hexadecimal value of the character) with the corresponding character. In addition, it replaces '+' with a space character (ie, + is equivalent to %20). Any other sequences following a % will be ignored. >>> percentDecode('q=M%26%25%26%25%3B+S') 'q=M&%&%; S' >>> percentDecode('%C2%A3') '\xc2\xa3' """ value = value if isinstance(value, unicode): value = value.encode('utf-8') value = value.replace('+', ' ') i = 0 result = [] while i != -1: j = value.find('%', i) if j == -1: result.append(value[i:]) break if j != i: result.append(value[i:j]) # Everything before position j has now been added to result. hexdigits = value[j + 1 : j + 3] try: hexval = int(hexdigits, 16) result.append(chr(hexval)) i = j + 3 except ValueError: result.append(value[j]) i = j + 1 return ''.join(result) _markupre = re.compile (']*>') def stripMarkup (s): """ Strip all markup () out of the supplied string. """ return _markupre.sub ('', s) _wikitags = { "''":'i', "'''":'b', '`':'tt', '__':'u', '^':'sup', ',,':'sub', '~-':'small', '~+':'big' } _ent_re = re.compile ('&#x[\da-fA-F]+;|&#\d+;|&\w+;') def ents2uni (s): """ Substitute unicode characters for common HTML entities. This returns a unicode string. """ def _subst (mo): ms = mo.group(0).lower() if ms.startswith ('&#x'): return unichr (int (ms[3:-1], 16)) elif ms.startswith ('&#'): return unichr (int (ms[2:-1])) elif ms.startswith ('&'): try: return unichr (htmlentitydefs.name2codepoint[ms[1:-1]]) except KeyError: return ms else: return '' return _ent_re.sub (_subst, unicode (s)) _js_slash = { '"':'\\"', '\n':'\\n', '\r':'\\r' } def js_encode (s): """ Encode a unicode string in Javascript literal form. """ if isinstance (s, str): return s ret = [] for c in s: if c in _js_slash: ret.append (_js_slash[c]) elif ord(c) < 128: ret.append (str(c)) else: ret.append ('\\u%04x' % ord(c)) return ''.join (ret) __tests__ = { "Invalid % sequences to decode": """ >>> print percentDecode('%') % >>> print percentDecode('%') % >>> print percentDecode('foo%') foo% >>> print percentDecode('foo%%') foo%% >>> print percentDecode('foo%7g') foo%7g >>> print percentDecode('foo+%%20%') foo % % """ } if __name__ == "__main__": import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/perftest/parse_wikipedia/XMLUtils.py0000644000175000017500000012744710667526240021407 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2006 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import xml.dom.minidom import xml.dom.pulldom import xml.parsers.expat import xml.sax import copy, re import Errors, HTMLUtils class ParsedXmlTextGetter: """ Class used to implement the process of extracting the textual contents of some XML. Implemented as a class rather than a method so that the setup process can be shared between calls. """ __spaces_re = re.compile(r'\s+') def __init__(self, nospacetags=None, spacetags=None, ignoretags=None, requiretags=None, condenseSpaces=False, caseInsensitiveTags=False): """Set up a text getter. `nospacetags` is a sequence of tags where the tags should be discarded, but the contents preserved. `spacetags` is a sequence of tags where the tags should be replaced by whitespace, but the contents preserved. `ignoretags` is a sequence of tags which should be ignored completely. `requiretags` is a sequence of tags which, if supplied, will cause any content not contained in one of the tags to be ignored completely. `condenseSpaces` is a flag; if True, all sequences of whitespace in the output will be replaced by a single space, and whitespace will be stripped from the start and end of the result. `caseInsensitiveTags` is a flag; if True, all tag names will be matched in a case insensitive manner. Any tags which are found which are not in one of the above lists will be treated as if it were in spacetags. (Future implementations may raise an error here, or be configurable, however.) """ if nospacetags is None: nospacetags = set() else: nospacetags = set(nospacetags) if spacetags is None: spacetags = set() else: spacetags = set(spacetags) if ignoretags is None: ignoretags = set() else: ignoretags = set(ignoretags) if requiretags is not None: requiretags = set(requiretags) if nospacetags.intersection(spacetags): raise ValueError, "Tags may not be shared between nospacetags and spacetags" if nospacetags.intersection(ignoretags): raise ValueError, "Tags may not be shared between nospacetags and ignoretags" if spacetags.intersection(ignoretags): raise ValueError, "Tags may not be shared between spacetags and ignoretags" if requiretags is not None and ignoretags.intersection(requiretags): raise ValueError, "Tags may not be shared between ignoretags and requiretags" if caseInsensitiveTags: if requiretags is not None: requiretags = set((item.lower() for item in requiretags)) nospacetags = set((item.lower() for item in nospacetags)) spacetags = set((item.lower() for item in spacetags)) ignoretags = set((item.lower() for item in ignoretags)) self._nospacetags = nospacetags self._spacetags = spacetags self._ignoretags = ignoretags self._requiretags = requiretags self._condenseSpaces = condenseSpaces self._caseInsensitiveTags = caseInsensitiveTags def toText(self, parsedXml): """ Convert a parsedXML object to text, according to the rules set up in this getter. """ text = u'' ignoring = 0 # Count of number of ignore tags we're within required = 0 # Count of number of require tags we're within if self._requiretags is None: required = 1 # Pretend we're always within a require tag for item in parsedXml.getItems(): if item.type == ParsedXmlItem.START: name = item.nodeNames[-1] if self._caseInsensitiveTags: name = name.lower() if self._requiretags is not None and name in self._requiretags: required += 1 if name in self._ignoretags: ignoring += 1 elif ignoring == 0 and required != 0: if name in self._nospacetags: pass elif name in self._spacetags: text += u' ' else: text += u' ' elif item.type == ParsedXmlItem.END: name = item.nodeNames[-1] if self._caseInsensitiveTags: name = name.lower() if name in self._ignoretags: ignoring -= 1 elif ignoring == 0 and required != 0: if name in self._nospacetags: pass elif name in self._spacetags: text += u' ' else: text += u' ' if self._requiretags is not None and name in self._requiretags: required -= 1 elif item.type == ParsedXmlItem.DATA: if ignoring == 0 and required != 0: text += item.data if self._condenseSpaces: text = self.__spaces_re.sub(' ', text).strip() return text class ParsedXmlItem: """ Class representing an item of XML. This is either the start of an element, the end of an element, or a piece of textual data. """ START = 0 END = 1 DATA = 2 typenames = { START: "START", END: "END", DATA: "DATA", } def __init__(self, type, nodeNames, atts=None, data=None, node=None, unlinker=None): self.type = type self.nodeNames = nodeNames self.atts = atts self.data = data self._node = node self._unlinker = unlinker def expand(self): assert self.type == self.START, 'Cannot expand() when item is not a START item' expanded = ParsedXml() expanded._node = self._node expanded._unlinker = self._unlinker return expanded def getAttr(self, name, default=None): """Return the attribute of the given name. If not found, returns default. """ try: return self.atts[name].nodeValue except KeyError: return default def __str__(self): extra=u'' if self.atts is not None: for i in xrange(len(self.atts)): att = self.atts.item(i) extra += u" %s='%s'" % (att.name, att.nodeValue) if self.data is not None: extra += u' data=%s' % repr(self.data) if len(extra) != 0: extra = u',' + extra return u'(%s, %s%s)' % ( self.typenames[self.type], repr(self.nodeNames), extra ) def __repr__(self): extra='' if self.atts is not None: extra += ', atts=%s' % repr(self.atts) if self.data is not None: extra += ', data=%s' % repr(self.data) return 'ParsedXmlItem(ParsedXmlItem.%s, %s%s)' % ( self.typenames[self.type], repr(self.nodeNames), extra ) def toxml (self): """ Return this tag/data formatted as XML. """ if self.type == self.START: ret = ['<%s' % self.nodeNames[-1]] for i in xrange(len(self.atts)): att = self.atts.item (i) ret.append (u' %s="%s"' % (att.name, HTMLUtils.encodeText (att.nodeValue))) ret.append ('>') return ''.join (ret) elif self.type == self.END: return '' % self.nodeNames[-1] else: return HTMLUtils.encodeText (self.data) def _convertParseExceptions(callable, xmlString=None): """ Convert exceptions raised by XML parsers to UserErrors describing the error. """ try: return callable() except xml.parsers.expat.ExpatError, e: context = '' if xmlString: try: lines = xmlString.split('\n') pos = max(e.offset - 10, 0) line = lines[e.lineno - 1] context = " (near %s)" % HTMLUtils.encodeText(line[pos:pos + 20]) context = context.replace('%', '%%') except: pass raise Errors.UserError("at line %%s, column %%s%s: %%s" % context, e.lineno, e.offset, xml.parsers.expat.ErrorString(e.code)) except xml.sax.SAXParseException, e: context = '' if xmlString: try: lines = xmlString.split('\n') pos = max(e.getColumnNumber() - 10, 0) line = lines[e.getLineNumber() - 1] context = " (near %s)" % HTMLUtils.encodeText(line[pos:pos + 20]) context = context.replace('%', '%%') except: pass raise Errors.UserError("at line %%s, column %%s%s: %%s" % context, e.getLineNumber(), e.getColumnNumber(), e.getMessage()) except ValueError, e: raise Errors.UserError("Parse error: %s", str(e)) class ParsedXml: """ Class representing a parsed piece of XML, and providing several convenience methods for getting at the parsed XML. The parsed piece of XML is a single well-formed tag (ie, has exactly one root node). """ def __init__(self, xmlString=None): """Initialise the ParsedXml object. If xmlString is supplied (and not None), it should contain either a unicode object or utf-8 encoded string object. If fh is supplied, it should be a filehandle which is open for reading, and is pointing to the start of an XML file. Only one of xmlString and fh may be supplied. """ # A DOM node representing the parsed XML. # Used if reading from a string. self._node = None # The parsedXml object which should call unlink() on _node, or None if # this is the object which should do that. # This is used to ensure that the object which calls unlink isn't # garbage collected (and hence calls unlink) before all users have # finished, and hence released their references to it. self._unlinker = None # Parse the string: if xmlString is not None: self._parseFragment(xmlString) def __del__(self): """ Free the internals. This avoids cyclic garbage collection being needed. """ if self._node is not None: if self._unlinker is None: self._node.unlink() self._node = None self._unlinker = None def getAsString(self): """Get the parsed piece of XML as a utf-8 string. """ if self._node is not None: return self._node.toxml('utf-8') def getContentsAsString(self): """Get the contents of the parsed piece of XML. This returns the contents as a utf-8 string. This includes the contents of the root tag, but not the root tag itself. """ if not self._node.hasChildNodes: return '' contents = [] currnode = self._node.firstChild while currnode is not None: contents.append(currnode.toxml('utf-8')) currnode = currnode.nextSibling return ''.join(contents) def getText(self, *args, **kwargs): """ Get the textual contents of this piece of XML, as a unicode string. See the documentation for ParsedXmlTextGetter.__init__() for details of the parameters. """ getter = ParsedXmlTextGetter(*args, **kwargs) return getter.toText(self) def _parseFragment(self, xmlString): """ Parse a fragment of XML, storing the resulting DOM node in this ParsedXml object. """ if isinstance(xmlString, unicode): # Convert to utf-8 xmlString = xmlString.encode('utf-8') result = [] def callable(): result.append(xml.dom.minidom.parseString(xmlString)) _convertParseExceptions(callable, xmlString) # Don't call unlink on the old value of _node: we can't guarantee that # noone is using it, so we just have to wait for cyclic garbage # collection to pick it up. self._node = result[0] self._unlinker = None def getItems(self): """Return an iterator which returns all the items in the parsed XML. """ root = self._node if root is None: return iter(()) if root.nodeType == root.DOCUMENT_NODE: root = root.documentElement class Iter: def __init__(self, root, unlinker): self._unlinker = unlinker self._nodelist = [[root, None]] self._nodeNames = [] def __iter__(self): 'Method needed to satisfy iterator protocol.' return self def next(self): 'Move to next element, or throw StopIteration.' if len(self._nodelist) == 0: raise StopIteration while len(self._nodelist) != 0: (node, subpos) = self._nodelist[-1] if node.nodeType == node.ELEMENT_NODE: if subpos is None: # Haven't returned start of node yet. self._nodeNames.append(node.nodeName) self._nodelist[-1][1] = 0 return ParsedXmlItem(ParsedXmlItem.START, self._nodeNames, atts=node.attributes, node=node, unlinker=self._unlinker) else: # Get next subnode which we care about. while True: if subpos >= len(node.childNodes): break newnode = node.childNodes[subpos] subpos += 1 if newnode.nodeType == newnode.ELEMENT_NODE: # Have an element node self._nodelist[-1][1] = subpos self._nodelist.append([newnode, 0]) self._nodeNames.append(newnode.nodeName) return ParsedXmlItem(ParsedXmlItem.START, self._nodeNames, atts=newnode.attributes, node=newnode, unlinker=self._unlinker) elif newnode.nodeType == newnode.TEXT_NODE or newnode.nodeType == newnode.CDATA_SECTION_NODE: # Have a text node - join it with any subsequent text nodes. result = ParsedXmlItem(ParsedXmlItem.DATA, self._nodeNames, data=newnode.data) resultdata = [result.data] while subpos < len(node.childNodes): nextnode = node.childNodes[subpos] if nextnode.nodeType == nextnode.ELEMENT_NODE: # An element - need to leave this # to be dealt with later. break elif nextnode.nodeType == nextnode.TEXT_NODE or nextnode.nodeType == nextnode.CDATA_SECTION_NODE: # More text - add it to this node. resultdata.append(nextnode.data) else: pass subpos += 1 result.data = u''.join(resultdata) self._nodelist[-1][1] = subpos return result else: # Have a node which is neither text nor an element. # Skip it. pass # No more subnodes - return end of parent node. result = ParsedXmlItem(ParsedXmlItem.END, copy.copy(self._nodeNames), atts=node.attributes) self._nodeNames.pop() self._nodelist.pop() return result elif node.nodeType == node.TEXT_NODE or node.nodeType == node.CDATA_SECTION_NODE: # Have a text node self._nodelist.pop() return ParsedXmlItem(ParsedXmlItem.DATA, self._nodeNames, data=node.data) else: # Have a node which is neither text nor an element. # Skip it. pass def expand(self): """ Expand the current item (and its subitems) by returning a ParsedXml object representing the current item. Only valid when the current item (ie, last returned by next()) is a START item. See also the skipContents() method, which is often useful in conjunction with this method. """ assert self._nodelist[-1][1] != 0, 'Cannot expand() when current item is not a START item' expanded = ParsedXml() expanded._node = self._nodelist[-1][0] expanded._unlinker = self._unlinker return expanded def skipContents(self): """ If the current item is a START item, advances the iterator such that the next item is the corresponding END item. Otherwise, has no effect. """ if self._nodelist[-1][1] != 0: return self._nodelist[-1][1] = len(self._nodelist[-1][0].childNodes) if self._unlinker is None: return Iter(root, self) else: return Iter(root, self._unlinker) class ParsedXmlFileItem(ParsedXmlItem): """Class representing an item of XML read from a file. This is either the start of an element, the end of an element, or a piece of textual data. """ def __init__(self, type, nodeNames, atts=None, data=None, node=None, unlinker=None, expander=None): ParsedXmlItem.__init__(self, type, nodeNames, atts=atts, data=data, node=node, unlinker=unlinker) self._expander = expander def expand(self): """Expand the item, by returning a ParsedXml object representing the current item. Note that this is only valid if the iterator that this ParsedXmlFileItem came from hasn't moved since making this ParsedXmlFileItem. """ return self._expander.expand(node=self._node) def __repr__(self): extra='' if self.atts is not None: extra += ', atts=%s' % repr(self.atts) if self.data is not None: extra += ', data=%s' % repr(self.data) return 'ParsedXmlFileItem(ParsedXmlItem.%s, %s%s)' % ( self.typenames[self.type], repr(self.nodeNames), extra ) class ParsedXmlFile(ParsedXml): """Class representing a parsed XML file. The file is actually read and parsed lazily, but this implementation is hidden, and the interface provided is precisely that of ParsedXml. """ def __init__(self, fh): ParsedXml.__init__(self, None) # File handle that file is being read from. # Used if reading from a file. self._fh = None # Position in file handle that XML starts at. # Used if reading from a file. self._startpos = None # If we've been supplied a filename instead of a file handle, try # opening it. if isinstance(fh, basestring): try: handle = open(fh) except IOError, e: raise Errors.UserError("Can't open file %s: %s", fh, str(e)) fh = handle # Store the file handle and current position, for use when we start # reading the file. if fh is not None: self._fh = fh self._startpos = fh.tell() def _getParseEvents(self): """Parse from a file handle. This uses the pulldom interfsce to avoid having to read in the whole file at once. It returns a DOMEventStream object, which provides a stream of parse events. """ if self._fh.tell() != self._startpos: self._fh.seek(self._startpos) result = [] def callable(): result.append(xml.dom.pulldom.parse(self._fh)) _convertParseExceptions(callable) return result[0] def getAsString(self): """Get the parsed piece of XML as a utf-8 string. """ events = self._getParseEvents() result = [] def callable(): for (event, node) in events: if event == "START_ELEMENT": events.expandNode(node) result.append(node.toxml()) _convertParseExceptions(callable) return ''.join(result) def getContentsAsString(self): """Get the contents of the parsed piece of XML. This returns the contents as a utf-8 string. This includes the contents of the root tag, but not the root tag itself. """ events = self._getParseEvents() result = [] def callable(): for (event, node) in events: if event == "START_ELEMENT": break for (event, node) in events: if event == "START_ELEMENT": events.expandNode(node) result.append(node.toxml()) if event == "END_ELEMENT": break _convertParseExceptions(callable) return ''.join(result) def getItems(self): """ Return an iterator which returns all the items in the parsed XML. """ class Iter: def __init__(self, events, unlinker): self._events = events self._unlinker = unlinker self._nodeNames = [] self._lastEvent = None self._lastNode = None self._nextItem = None self._expandedIter = None self._expandedIterStarted = False self._expandedXml = None def callable(): while True: self._nextItem = self._events.next() if self._nextItem[0] == 'START_ELEMENT': break try: _convertParseExceptions(callable) except StopIteration: self._events = None def __iter__(self): 'Method needed to satisfy iterator protocol.' return self def next(self): 'Move to next element, or throw StopIteration.' # If we've got an expanded iterator, pass through items from # the iterator over the expanded node, but add the preceding # nodenames to it. if self._expandedIter is not None: try: item = self._expandedIter.next() self._expandedIterStarted = True newNodeNames = [] newNodeNames.extend(self._nodeNames[:-1]) newNodeNames.extend(item.nodeNames) item.nodeNames = newNodeNames return item except StopIteration: self._expandedIter = None self._expandedXml = None self._expandedIterStarted = False self._nodeNames.pop() # Read events from the file, merging any character events, and # return ParsedXmlFileItems for each one. while True: # If we haven't already read ahead by one, read the next # event. if self._nextItem is None: if self._events is None: raise StopIteration def callable(): self._nextItem = self._events.next() try: _convertParseExceptions(callable) except StopIteration: self._events = None raise (self._lastEvent, self._lastNode) = self._nextItem self._nextItem = None if self._lastEvent is None: raise StopIteration # Now return a node based on self._lastEvent and self._lastNode if self._lastEvent == 'START_ELEMENT': # Return start of node self._nodeNames.append(self._lastNode.nodeName) return ParsedXmlFileItem(ParsedXmlFileItem.START, self._nodeNames, atts=self._lastNode.attributes, node=self._lastNode, unlinker=self._unlinker, expander=self) elif self._lastEvent == 'CHARACTERS': # Text data in the node. # Move forward merging CHARACTERS nodes together, until # we have a different type of node. characters = [self._lastNode.data] def callable(): while self._nextItem is None: self._nextItem = self._events.next() if self._nextItem[0] == 'CHARACTERS': characters.append(self._nextItem[1].data) self._nextItem = None try: _convertParseExceptions(callable) except StopIteration: self._nextItem = None self._events = None return ParsedXmlFileItem(ParsedXmlFileItem.DATA, self._nodeNames, data=''.join(characters)) elif self._lastEvent == 'END_ELEMENT': # End of a node. result = ParsedXmlFileItem(ParsedXmlFileItem.END, copy.copy(self._nodeNames), atts=self._lastNode.attributes) self._nodeNames.pop() return result else: # Something else: ignore it, go round the loop again. pass def expand(self, node=None): """ Expand the current item (and its subitems) by returning a ParsedXml object representing the current item. Only valid when the current item (ie, last returned by next()) is a START item. See also the skipContents() method, which is often useful in conjunction with this method. If node is supplied, will raise an error if the supplied node is not the last node supplied. """ if self._expandedIter is not None: if self._expandedIterStarted: return self._expandedIter.expand() else: return self._expandedXml assert node is None or node is self._lastNode assert self._lastEvent == 'START_ELEMENT', 'Cannot expand() when current item is not a START item' def callable(): self._events.expandNode(self._lastNode) _convertParseExceptions(callable) self._expandedXml = ParsedXml() self._expandedXml._node = self._lastNode self._expandedXml._unlinker = self._unlinker self._expandedIter = self._expandedXml.getItems() self._expandedIterStarted = False try: self._expandedIter.next() except StopIteration: self._expandedIter = None self._expandedXml = None return self._expandedXml def skipContents(self): """ If the current item is a START item, advances the iterator such that the next item is the corresponding END item. Otherwise, has no effect. """ if self._lastEvent != 'START_ELEMENT': return if self._expandedXml: self._expandedIter.skipContents() return def callable(): nodeNames = [self._lastNode.nodeName] while len(nodeNames) != 0: if self._nextItem is not None: (self._lastEvent, self._lastNode) = self._nextItem self._nextItem = self._events.next() print self._nextItem, nodeNames (event, node) = self._nextItem if event == 'START_ELEMENT': nodeNames.append(node.nodeName) elif event == 'END_ELEMENT': assert nodeNames[-1] == node.nodeName nodeNames.pop() try: _convertParseExceptions(callable) except StopIteration: self._nextItem = None return Iter(self._getParseEvents(), self) __test__ = { 'Getting items': r""" Get some items, and check that all the subitems expand correctly. >>> parsed=ParsedXml('A') >>> for item in parsed.getItems(): ... print "Item:", item ... if item.type == item.START: ... subparsed = item.expand() ... for item2 in subparsed.getItems(): ... print "Item2:", item2 Item: (START, [u'b'], a='' c='' b='') Item2: (START, [u'b'], a='' c='' b='') Item2: (START, [u'b', u'a']) Item2: (DATA, [u'b', u'a'], data=u'A') Item2: (END, [u'b', u'a']) Item2: (END, [u'b'], a='' c='' b='') Item: (START, [u'b', u'a']) Item2: (START, [u'a']) Item2: (DATA, [u'a'], data=u'A') Item2: (END, [u'a']) Item: (DATA, [u'b', u'a'], data=u'A') Item: (END, [u'b', u'a']) Item: (END, [u'b'], a='' c='' b='') Get some items, and check that all the subitems expand correctly. >>> parsed=ParsedXml('A') >>> it = parsed.getItems() >>> for item in it: ... print "Item:", item ... if item.type == item.START and item.nodeNames[-1] == 'a': ... it.skipContents() ... subparsed = item.expand() ... it.skipContents() ... for item2 in subparsed.getItems(): ... print "Item2:", item2 Item: (START, [u'b'], a='' c='' b='') Item: (START, [u'b', u'a']) Item2: (START, [u'a']) Item2: (DATA, [u'a'], data=u'A') Item2: (END, [u'a']) Item: (END, [u'b', u'a']) Item: (END, [u'b'], a='' c='' b='') Check that iterator now raises StopIteration >>> it.next() Traceback (most recent call last): ... StopIteration First, just parse some simple XML and check that the element list is right. >>> parsed=ParsedXml('Normal italic italicbold normalagain mixed.') >>> for item in parsed.getItems(): print item (START, [u'field'], name='title') (DATA, [u'field'], data=u'Normal ') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'italic ') (START, [u'field', u'i', u'b']) (DATA, [u'field', u'i', u'b'], data=u'italicbold') (END, [u'field', u'i', u'b']) (END, [u'field', u'i']) (DATA, [u'field'], data=u' normalagain mi') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'x') (END, [u'field', u'i']) (DATA, [u'field'], data=u'ed.') (END, [u'field'], name='title') Next, parse some XML with an SGML comment. Should get exactly the same output. >>> parsed=ParsedXml('Normal italic italicbold normalagain mixed.') >>> for item in parsed.getItems(): print item (START, [u'field'], name='title') (DATA, [u'field'], data=u'Normal ') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'italic ') (START, [u'field', u'i', u'b']) (DATA, [u'field', u'i', u'b'], data=u'italicbold') (END, [u'field', u'i', u'b']) (END, [u'field', u'i']) (DATA, [u'field'], data=u' normalagain mi') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'x') (END, [u'field', u'i']) (DATA, [u'field'], data=u'ed.') (END, [u'field'], name='title') Now, convert some XML to text. >>> parsed=ParsedXml('Normal italic italicbold normalagain mixed.') >>> print parsed.getText(nospacetags=['field', 'i', 'b']) Normal italic italicbold normalagain mixed. >>> for item in parsed.getItems(): ... if item.type == item.START and item.nodeNames[-1] == 'i': ... print item.expand().getText(nospacetags=['i', 'b']) italic italicbold x Check if parameters supplied to the getText() method work. >>> for item in parsed.getItems(): ... if item.type == item.START and item.nodeNames[-1] == 'i': ... print item.expand().getText(spacetags=['b'], nospacetags=['i']) italic italicbold x >>> parsed=ParsedXml('C1B1C2A1B2C3A2') >>> for item in parsed.getItems(): ... if item.type == item.START: ... expanded = item.expand() ... print expanded.getAsString() ... print expanded.getContentsAsString() ... print item.expand().getText(nospacetags=['b', 'a']) ... print item.expand().getText(nospacetags=['b', 'a'], spacetags=['c']) ... print item.expand().getText(spacetags=['b']) ... print item.expand().getText(nospacetags=['a'], ignoretags=['c']) ... print item.expand().getText(ignoretags=['b']) ... print '.' #doctest: +REPORT_NDIFF C1B1C2A1B2C3A2 C1B1C2A1B2C3A2 C1 B1 C2 A1B2 C3 A2 C1 B1 C2 A1B2 C3 A2 C1 B1 C2 A1 B2 C3 A2 B1 A1 B2 A2 A1 C3 A2 . C1B1C2 C1B1C2 C1 B1 C2 C1 B1 C2 C1 B1 C2 B1 . C1 C1 C1 C1 C1 C1 . C2 C2 C2 C2 C2 C2 . B2 B2 B2 B2 B2 B2 . C3 C3 C3 C3 C3 C3 . """, 'Getting items from file': r""" Get some items, and check that all the subitems expand correctly. >>> import StringIO >>> iostring = StringIO.StringIO('A') >>> parsed=ParsedXmlFile(iostring) >>> for item in parsed.getItems(): ... print "Item:", item ... if item.type == item.START: ... subparsed = item.expand() ... for item2 in subparsed.getItems(): ... print "Item2:", item2 #doctest: +REPORT_NDIFF Item: (START, [u'b'], a='' c='' b='') Item2: (START, [u'b'], a='' c='' b='') Item2: (START, [u'b', u'a']) Item2: (DATA, [u'b', u'a'], data=u'A') Item2: (END, [u'b', u'a']) Item2: (END, [u'b'], a='' c='' b='') Item: (START, [u'b', u'a']) Item2: (START, [u'a']) Item2: (DATA, [u'a'], data=u'A') Item2: (END, [u'a']) Item: (DATA, [u'b', u'a'], data=u'A') Item: (END, [u'b', u'a']) Item: (END, [u'b'], a='' c='' b='') """, 'Get items from file and check expand': r""" Get some items, and check that all the subitems expand correctly. >>> import StringIO >>> parsed=ParsedXmlFile(StringIO.StringIO('A')) >>> it = parsed.getItems() >>> for item in it: ... print "Item:", item ... if item.type == item.START and item.nodeNames[-1] == 'a': ... subparsed = item.expand() ... it.skipContents() ... it.skipContents() ... for item2 in subparsed.getItems(): ... print "Item2:", item2 #doctest: +REPORT_NDIFF Item: (START, [u'b'], a='' c='' b='') Item: (START, [u'b', u'a']) Item2: (START, [u'a']) Item2: (DATA, [u'a'], data=u'A') Item2: (END, [u'a']) Item: (END, [u'b', u'a']) Item: (END, [u'b'], a='' c='' b='') Check that iterator now raises StopIteration >>> it.next() Traceback (most recent call last): ... StopIteration Check that if skipContents() is not used, the results are the same whether expand is called or not. >>> it = parsed.getItems() >>> for item in it: ... print "Item:", item ... if item.type == item.START and item.nodeNames[-1] == 'a': ... subparsed = item.expand() ... for item2 in subparsed.getItems(): ... print "Item2:", item2 #doctest: +REPORT_NDIFF Item: (START, [u'b'], a='' c='' b='') Item: (START, [u'b', u'a']) Item2: (START, [u'a']) Item2: (DATA, [u'a'], data=u'A') Item2: (END, [u'a']) Item: (DATA, [u'b', u'a'], data=u'A') Item: (END, [u'b', u'a']) Item: (END, [u'b'], a='' c='' b='') Check that iterator now raises StopIteration >>> it.next() Traceback (most recent call last): ... StopIteration >>> it = parsed.getItems() >>> for item in it: ... print "Item:", item ... if item.type == item.START and item.nodeNames[-1] == 'a': ... subparsed = item.expand() #doctest: +REPORT_NDIFF Item: (START, [u'b'], a='' c='' b='') Item: (START, [u'b', u'a']) Item: (DATA, [u'b', u'a'], data=u'A') Item: (END, [u'b', u'a']) Item: (END, [u'b'], a='' c='' b='') Check that iterator now raises StopIteration >>> it.next() Traceback (most recent call last): ... StopIteration >>> it = parsed.getItems() >>> for item in it: ... print "Item:", item #doctest: +REPORT_NDIFF Item: (START, [u'b'], a='' c='' b='') Item: (START, [u'b', u'a']) Item: (DATA, [u'b', u'a'], data=u'A') Item: (END, [u'b', u'a']) Item: (END, [u'b'], a='' c='' b='') Check that iterator now raises StopIteration >>> it.next() Traceback (most recent call last): ... StopIteration """, 'Parse XML from file': r""" First, just parse some simple XML and check that the element list is right. >>> import StringIO >>> parsed=ParsedXmlFile(StringIO.StringIO('Normal italic italicbold normalagain mixed.')) >>> for item in parsed.getItems(): print item #doctest: +REPORT_NDIFF (START, [u'field'], name='title') (DATA, [u'field'], data=u'Normal ') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'italic ') (START, [u'field', u'i', u'b']) (DATA, [u'field', u'i', u'b'], data=u'italicbold') (END, [u'field', u'i', u'b']) (END, [u'field', u'i']) (DATA, [u'field'], data=u' normalagain mi') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'x') (END, [u'field', u'i']) (DATA, [u'field'], data=u'ed.') (END, [u'field'], name='title') """, 'Parse XML with SGML comment from file': r""" Next, parse some XML with an SGML comment. Should get exactly the same output. >>> import StringIO >>> parsed=ParsedXmlFile(StringIO.StringIO('Normal italic italicbold normalagain mixed.')) >>> for item in parsed.getItems(): print item #doctest: +REPORT_NDIFF (START, [u'field'], name='title') (DATA, [u'field'], data=u'Normal ') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'italic ') (START, [u'field', u'i', u'b']) (DATA, [u'field', u'i', u'b'], data=u'italicbold') (END, [u'field', u'i', u'b']) (END, [u'field', u'i']) (DATA, [u'field'], data=u' normalagain mi') (START, [u'field', u'i']) (DATA, [u'field', u'i'], data=u'x') (END, [u'field', u'i']) (DATA, [u'field'], data=u'ed.') (END, [u'field'], name='title') """, 'Parse XML from file and convert to text': r""" Now, convert some XML to text. >>> import StringIO >>> parsed=ParsedXmlFile(StringIO.StringIO('Normal italic italicbold normalagain mixed.')) >>> print parsed.getText(nospacetags=['field', 'i', 'b']) Normal italic italicbold normalagain mixed. >>> for item in parsed.getItems(): ... if item.type == item.START and item.nodeNames[-1] == 'i': ... print item.expand().getText(nospacetags=['i', 'b']) italic italicbold x Check if parameters supplied to the getText() method work. >>> for item in parsed.getItems(): ... if item.type == item.START and item.nodeNames[-1] == 'i': ... print item.expand().getText(spacetags=['b'], nospacetags=['i']) italic italicbold x >>> parsed=ParsedXmlFile(StringIO.StringIO('C1B1C2A1B2C3A2')) >>> for item in parsed.getItems(): ... if item.type == item.START: ... expanded = item.expand() ... print expanded.getAsString() ... print expanded.getContentsAsString() ... print item.expand().getText(nospacetags=['b', 'a']) ... print item.expand().getText(nospacetags=['b', 'a'], spacetags=['c']) ... print item.expand().getText(spacetags=['b']) ... print item.expand().getText(nospacetags=['a'], ignoretags=['c']) ... print item.expand().getText(ignoretags=['b']) ... print '.' #doctest: +REPORT_NDIFF C1B1C2A1B2C3A2 C1B1C2A1B2C3A2 C1 B1 C2 A1B2 C3 A2 C1 B1 C2 A1B2 C3 A2 C1 B1 C2 A1 B2 C3 A2 B1 A1 B2 A2 A1 C3 A2 . C1B1C2 C1B1C2 C1 B1 C2 C1 B1 C2 C1 B1 C2 B1 . C1 C1 C1 C1 C1 C1 . C2 C2 C2 C2 C2 C2 . B2 B2 B2 B2 B2 B2 . C3 C3 C3 C3 C3 C3 . """ } if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/perftest/parse_wikipedia/wiki2dump.py0000755000175000017500000001506010667526240021627 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2006 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """wiki2dump.py: Convert wikimedia xml dump files to scriptindex input files. Usage: ./wiki2dump.py Outputs result to standard output. """ import sys import os.path from XMLUtils import ParsedXmlFile from Errors import UserError import re class PageRevision: """A revision of a wikimedia page. This has an id number, timestamp, contributor_name, contributor_id, minor edit flag, comment, and text. """ _re_redirect = re.compile('#REDIRECT\s*\[\[(?P.*?)\]\]', re.IGNORECASE) def __init__(self, xml): self.id = None self.timestamp = None self.contributor_name = '' self.contributor_id = None self.minor = False self.comment = '' self.text = '' self.redirect = None it = xml.getItems() for item in it: if item.type == item.DATA: if item.nodeNames[-2:] == [u'contributor', u'username']: self.contributor_name = item.data elif item.nodeNames[-2:] == [u'contributor', u'id']: self.contributor_id = item.data # FIXME - convert (checked) to int elif item.nodeNames[-1] == u'id': self.id = item.data # FIXME - convert (checked) to int if item.nodeNames[-1] == u'timestamp': self.timestamp = item.data # FIXME - convert (checked) to datetime if item.nodeNames[-1] == u'comment': self.comment = item.data if item.nodeNames[-1] == u'text': self.text = item.data elif item.type == item.START: if item.nodeNames[-1] == u'minor': self.minor = True if len(self.text) > 0 and self.text[0] == '#': # Deal with special directives g = self._re_redirect.match(self.text) if g: self.redirect = g.group('target') def __repr__(self): return '' % ( self.id, self.timestamp, self.contributor_name, self.contributor_id, self.minor, self.comment, self.text, self.redirect, ) class Page: """A wikimedia page. This corresponds to a page tag in the input XML file. It has a title, id number, and a list of PageRevision objects (which will often contain only a single entry). """ def __init__(self, xml): self.title = None self.id = None self.revisions = [] it = xml.getItems() for item in it: if item.type == item.START: if item.nodeNames[-1] == 'revision': self.revisions.append(PageRevision(item.expand())) it.skipContents() elif item.type == item.DATA: if item.nodeNames[-1] == 'title': self.title = item.data elif item.nodeNames[-1] == 'id': self.id = item.data # FIXME - convert (checked) to int def dump(self): redirect = False result = [] if self.title is not None: result.append("title=%s" % self.title) if self.id is not None: result.append("id=%s" % self.id) maxrev = None for revision in self.revisions: if maxrev is None or maxrev.timestamp < revision.timestamp: maxrev = revision if maxrev is not None: if maxrev.redirect is not None: result.append("redirect=%s" % maxrev.redirect) redirect = True elif len(maxrev.text) > 0: text = maxrev.text.replace('\n', '\n=') result.append("text=%s" % text) return (u'\n'.join(result), redirect) def parse(infile, outfile, redirfile): infile_size = os.path.getsize(infile) infh = open(infile, "rb") if os.path.exists(outfile): raise UserError("Error: output file \"%s\" already exists.", outfile) if os.path.exists(redirfile): raise UserError("Error: redirections output file \"%s\" already exists.", redirfile) outfh = open(outfile, "wb") redirfh = open(redirfile, "wb") xml = ParsedXmlFile(infh) state = 0 it = xml.getItems() for item in it: if state == 0: if item.type != item.START: raise UserError('Didn\'t get correct header at start of file') else: state = 1 continue if state == 1: if item.type == item.START: if item.nodeNames[-1] == u'page': page = Page(item.expand()) (dump, redirect) = page.dump() if redirect: redirfh.write(dump.encode('utf-8')) redirfh.write('\n\n') else: outfh.write(dump.encode('utf-8')) outfh.write('\n\n') it.skipContents() pos = infh.tell() percent = 100.0 * pos / infile_size if redirect: print "Processed %f%%: %r (redirect to %r)" % (percent, page.title, redirect) else: print "Processed %f%%: %r" % (percent, page.title) infh.close() outfh.close() redirfh.close() # Start if len(sys.argv) != 4: print """ Usage: ./wiki2dump.py """.strip() sys.exit(0) infile = sys.argv[1] outfile = sys.argv[2] redirfile = sys.argv[3] try: parse(infile, outfile, redirfile) except UserError, e: print e xappy-0.5/perftest/analyse_indexlogs.py0000644000175000017500000002042710702531177020257 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import csv import pylab import sys def get_av_docspersec(times, interval, docscale): docspersec = [] docs = [] for i in xrange(interval, len(times)): docinterval = times[i].docs - times[i-interval].docs timeinterval = times[i].time - times[i-interval].time docspersec.append(docinterval / timeinterval) docs.append(times[i].docs / docscale) if interval >= len(times): return docspersec, docs, 0 else: return docspersec, docs, times[interval].docs - times[0].docs def calc_docscale(times): docscale = 1000 if len(times) > 2: docdiff = times[1].docs - times[0].docs while docscale > 1 and docdiff <= docscale: docscale //= 10 if docscale == 1: docscalestr = "" else: docscalestr = " (x%d)" % docscale return docscale, docscalestr def generate_figures(times, outprefix, pretitle): docscale, docscalestr = calc_docscale(times) # Generate a "total time" versus "total documents" plot if len(times) > 1: pylab.figure() total_times = [row.time / 3600.0 for row in times] total_documents = [row.docs / docscale for row in times] pylab.plot(total_times, total_documents) pylab.xlabel('Time (hours)') pylab.ylabel('Documents%s' % docscalestr) pylab.title(pretitle + r': documents indexed after a given time') pylab.axis([0, max(total_times) * 1.05, 0, max(total_documents) * 1.05]) pylab.savefig(outprefix + "totaltime_v_totaldocs.png", format="png") # Generate a "documents/second" plot docspersec_av1, docs_av1, docinterval = get_av_docspersec(times, 1, docscale) if len(docs_av1) > 1: pylab.figure() pylab.plot(docs_av1, docspersec_av1) pylab.xlabel('Documents%s' % docscalestr) pylab.ylabel('Docs per second') pylab.title(pretitle + ': indexing rate versus documents processed\nAveraged every %d documents' % docinterval) pylab.axis([0, max(docs_av1) * 1.05, 0, max(docspersec_av1) * 1.05]) pylab.savefig(outprefix + "docspersec_v_totaldocs_av1.png", format="png") docspersec_av10, docs_av10, docinterval = get_av_docspersec(times, 10, docscale) if len(docs_av10) > 1: pylab.figure() pylab.plot(docs_av10, docspersec_av10) pylab.xlabel('Documents%s' % docscalestr) pylab.ylabel('Docs per second') pylab.title(pretitle + ': indexing rate versus documents processed\nAveraged every %d documents' % docinterval) pylab.axis([0, max(docs_av10) * 1.05, 0, max(docspersec_av10) * 1.05]) pylab.savefig(outprefix + "docspersec_v_totaldocs_av10.png", format="png") docspersec_av100, docs_av100, docinterval = get_av_docspersec(times, 100, docscale) if len(docs_av100) > 1: pylab.figure() pylab.plot(docs_av100, docspersec_av100) pylab.xlabel('Documents%s' % docscalestr) pylab.ylabel('Docs per second') pylab.title(pretitle + ': indexing rate versus documents processed\nAveraged every %d documents' % docinterval) pylab.axis([0, max(docs_av100) * 1.05, 0, max(docspersec_av100) * 1.05]) pylab.savefig(outprefix + "docspersec_v_totaldocs_av100.png", format="png") def generate_comparison_figures(alltimes, outprefix, pretitle): docscale, docscalestr = calc_docscale(alltimes[0][1]) # Generate a "total time" versus "total documents" plot have_plotted = False xaxis = 0 yaxis = 0 for legend, times in alltimes: if len(times) > 1: if not have_plotted: pylab.figure() have_plotted = True total_times = [row.time / 3600.0 for row in times] total_documents = [row.docs / docscale for row in times] pylab.plot(total_times, total_documents, label=legend) xaxis = max(xaxis, max(total_times) * 1.05) yaxis = max(yaxis, max(total_documents) * 1.05) pylab.legend(loc="lower right") pylab.xlabel('Time (hours)') pylab.ylabel('Documents%s' % docscalestr) pylab.title(pretitle + r': documents indexed after a given time') pylab.axis([0, xaxis, 0, yaxis]) if have_plotted: pylab.savefig(outprefix + "totaltime_v_totaldocs.png", format="png") # Generate a "documents/second" plot have_plotted = False xaxis = 0 yaxis = 0 for legend, times in alltimes: docspersec_av1, docs_av1, docinterval = get_av_docspersec(times, 1, docscale) if len(docs_av1) > 1: if not have_plotted: pylab.figure() have_plotted = True pylab.plot(docs_av1, docspersec_av1, label=legend) xaxis = max(xaxis, max(docs_av1) * 1.05) yaxis = max(yaxis, max(docspersec_av1) * 1.05) pylab.legend(loc="lower left") pylab.xlabel('Documents%s' % docscalestr) pylab.ylabel('Docs per second') pylab.title(pretitle + ': indexing rate versus documents processed\nAveraged every %d documents' % docinterval) pylab.axis([0, xaxis, 0, yaxis]) if have_plotted: pylab.savefig(outprefix + "docspersec_v_totaldocs_av1.png", format="png") have_plotted = False xaxis = 0 yaxis = 0 for legend, times in alltimes: docspersec_av10, docs_av10, docinterval = get_av_docspersec(times, 10, docscale) if len(docs_av10) > 1: if not have_plotted: pylab.figure() have_plotted = True pylab.plot(docs_av10, docspersec_av10, label=legend) xaxis = max(xaxis, max(docs_av10) * 1.05) yaxis = max(yaxis, max(docspersec_av10) * 1.05) pylab.legend(loc="lower left") pylab.xlabel('Documents%s' % docscalestr) pylab.ylabel('Docs per second') pylab.title(pretitle + ': indexing rate versus documents processed\nAveraged every %d documents' % docinterval) pylab.axis([0, xaxis, 0, yaxis]) if have_plotted: pylab.savefig(outprefix + "docspersec_v_totaldocs_av10.png", format="png") have_plotted = False xaxis = 0 yaxis = 0 for legend, times in alltimes: docspersec_av100, docs_av100, docinterval = get_av_docspersec(times, 100, docscale) if len(docs_av100) > 1: if not have_plotted: pylab.figure() have_plotted = True pylab.plot(docs_av100, docspersec_av100, label=legend) xaxis = max(xaxis, max(docs_av100) * 1.05) yaxis = max(yaxis, max(docspersec_av100) * 1.05) pylab.legend(loc="lower left") pylab.xlabel('Documents%s' % docscalestr) pylab.ylabel('Docs per second') pylab.title(pretitle + ': indexing rate versus documents processed\nAveraged every %d documents' % docinterval) pylab.axis([0, xaxis, 0, yaxis]) if have_plotted: pylab.savefig(outprefix + "docspersec_v_totaldocs_av100.png", format="png") class logrow(object): __slots__ = ('docs', 'time', 'dbsize', 'tablesizes') def __init__(self, docs, time, dbsize, *tablesizes): self.docs = int(docs) self.time = float(time) self.dbsize = int(dbsize) self.tablesizes = [int(tablesize) for tablesize in tablesizes] def parse_logfile(filename): fd = open(filename) times = [] reader = csv.reader(fd) descline = reader.next() headings = reader.next() assert(','.join(headings) == 'Documents Added,Time(seconds),dbsize(bytes),inputsize(bytes)') for row in reader: newrow = logrow(*row) if len(times) > 0 and times[-1].docs == newrow.docs: times[-1] = newrow else: times.append(newrow) return descline, times xappy-0.5/perftest/analyse_searchlogs.py0000755000175000017500000000521610702541535020416 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import csv import pylab def get_stats(log): query_v_time = [(row.time, row.query) for row in log] query_v_time.sort() query_v_time.reverse() print "Average speed: %f seconds" % (sum((row.time for row in log)) / len(log)) print "Slowest queries:" for time, query in query_v_time[:10]: print "%s: %f seconds" % (query, time) def generate_figures(log, outprefix, pretitle): # Generate a "total time" versus "total documents" plot total_times = [row.tottime for row in log] query_times = [row.time for row in log] pylab.figure(figsize=(8,12)) pylab.subplot(311) pylab.plot(total_times) pylab.xlabel('Queries completed') pylab.ylabel('Total time (seconds)') pylab.title(pretitle + '\nQueries completed after given time') pylab.subplot(312) pylab.axis([0, len(query_times), 0, max(query_times) * 1.05]) pylab.plot(query_times) pylab.xlabel('Queries completed') pylab.ylabel('Query time (seconds)') pylab.title('Query times') pylab.subplot(313) pylab.axis([0, len(query_times), 0, 50]) pylab.hist(query_times, 50, log="true") pylab.xlabel('Query time (seconds)') pylab.ylabel('Queries') pylab.title('Query time histogram') pylab.savefig(outprefix + "query_times.png", format="png") class logrow(object): __slots__ = ('querynum', 'estmatches', 'time', 'tottime') def __init__(self, threadnum, querynum, matchcount, estmatches, time, tottime, querylen, *query): self.querynum = int(querynum) self.estmatches = int(estmatches) self.time = float(time) self.tottime = float(tottime) def parse_logfile(filename): fd = open(filename) times = [] titles = None reader = csv.reader(fd) for row in reader: if titles is None: titles = row else: newrow = logrow(*row) times.append(newrow) return times xappy-0.5/perftest/gen_queries.py0000755000175000017500000000444210667526240017064 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import random from sets import Set # Remove this line, or change to a different value, to get different output. random.seed(1) class WordSource: def __init__(self, infile): fd = open(infile, "r") words = Set() for line in fd.readlines(): line = line.replace('"', ' ') for word in line.split(): words.add(word) self.words = [] for word in words: self.words.append(word) def next(self): return random.choice(self.words) class QueryGenerator: def __init__(self, source, distribution): self.source = source self.distribution = [] for key, val in distribution.iteritems(): self.distribution.extend((key,) * val) def __iter__(self): return self def next(self): qlen = random.choice(self.distribution) qterms = [] while qlen > 0: qterms.append(self.source.next()) qlen -= 1 return ' '.join(qterms) def gen_queries(infile, outfile, limit, distribution): querygen = QueryGenerator(WordSource(infile), distribution) outfd = open(outfile, 'wb') count = 0 for query in querygen: query = query.replace('\n', ' ') outfd.write(query + '\n') count += 1 if count >= limit: break outfd.close() if __name__ == '__main__': infile = '../testdata/query_sourcewords.txt' outfile = '../testdata/queries.txt' limit = 100000 gen_queries(infile, outfile, limit, {1: 10, 2:3, 5:1}) xappy-0.5/perftest/indexer.py0000755000175000017500000001165710702544277016222 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import csv import os import sys import time import xappy class CsvLogger(object): def __init__(self, filepath): self.fd = open(filepath, 'ab') self.csvwriter = csv.writer(self.fd) def log(self, *args): self.csvwriter.writerow(args) self.fd.flush() def create_index(dbpath): """Create a new index, and set up its field structure. """ iconn = xappy.IndexerConnection(dbpath) iconn.add_field_action('title', xappy.FieldActions.STORE_CONTENT) iconn.add_field_action('title', xappy.FieldActions.INDEX_FREETEXT, language="en", weight=5) iconn.add_field_action('text', xappy.FieldActions.STORE_CONTENT) iconn.add_field_action('text', xappy.FieldActions.INDEX_FREETEXT, language='en') iconn.add_field_action('doclen', xappy.FieldActions.STORE_CONTENT) iconn.add_field_action('doclen', xappy.FieldActions.SORTABLE, type='float') iconn.add_field_action('doclen', xappy.FieldActions.COLLAPSE) iconn.close() def open_index(dbpath): """Open an existing index. """ return xappy.IndexerConnection(dbpath) def dirsize(dirname): size = 0 for dirpath, dirnames, filenames in os.walk(dirname): for filename in filenames: size += os.stat(os.path.join(dirpath, filename)).st_size return size def log_entry(logger, dbpath, addcount, starttime, inputsize): currtime = time.time() dbsize = dirsize(dbpath) logger.log(addcount, currtime - starttime, dbsize, inputsize) def index_scriptindex_file(iconn, dbpath, dumpfd, logger, flushspeed, maxdocs, logspeed): """Index a xapian "scriptindex" format file. """ logger.log("Documents Added", "Time(seconds)", "dbsize(bytes)", "inputsize(bytes)") starttime = time.time() linenum = 0 addcount = 0 doc = xappy.UnprocessedDocument() doclen = 0 inputsize = 0 fieldlen = 0 while maxdocs is None or addcount < maxdocs: line = dumpfd.readline() linenum += 1 if len(line) == 0: break inputsize += len(line) line = line.rstrip('\n\r') if len(line) == 0: if len(doc.fields) != 0: doc.fields.append(xappy.Field('doclen', doclen)) iconn.add(doc) addcount += 1 if flushspeed is not None and (addcount % flushspeed) == 0: iconn.flush() if addcount % logspeed == 0: log_entry(logger, dbpath, addcount, starttime, inputsize) doc = xappy.UnprocessedDocument() continue if line[0] == '#': continue equals = line.find("=") if equals == -1: raise ValueErrror("Missing '=' in line %d" % linenum) elif equals == 0: if len(doc.fields) == 0: raise ValueError("Continuation line %d is first in document" % linenum) else: doc.fields[-1].value += '\n' + line[1:] if doc.fields[-1].name == 'text': doclen = len(doc.fields[-1].value) else: doc.fields.append(xappy.Field(line[:equals], line[equals + 1:])) if doc.fields[-1].name == 'id': doc.id = doc.fields[-1].value elif doc.fields[-1].name == 'text': doclen = len(doc.fields[-1].value) # Add any left-over documents if len(doc.fields) != 0: doc.fields.append(xappy.Field('doclen', doclen)) iconn.add(doc) addcount += 1 iconn.flush() log_entry(logger, dbpath, addcount, starttime, inputsize) def index_file(inputfile, dbpath, logpath, flushspeed, description, maxdocs, logspeed): create_index(dbpath) iconn = open_index(dbpath) dumpfd = open(inputfile) logger = CsvLogger(logpath) descline = [description, "flushspeed=%d" % flushspeed] if maxdocs is not None: descline.append("maxdocs=%d" % maxdocs) if logspeed is not None: descline.append("logspeed=%d" % logspeed) logger.log(*descline) index_scriptindex_file(iconn, dbpath, dumpfd, logger, flushspeed, maxdocs, logspeed) xappy-0.5/perftest/parseargs.py0000755000175000017500000000273610677232134016546 0ustar richardrichard#!/usr/bin/env python """Parse command line arguments. """ import getopt import sys class Config(object): def __init__(self, **kwargs): for key, val in kwargs.iteritems(): setattr(self, key, val) def usage(exitval): print("Usage: perftest.py [options]") print("Options are:") print(" --help: Get help message") print(" --outdir: Set output directory") print(" --tmpdir: Set temporary directory") print(" --preserve: Preserve existing runs") sys.exit(exitval) def parse_argv(argv, **defaults): config = Config(**defaults) try: optlist, argv = getopt.gnu_getopt(argv, 'ho:t:p', ('help', 'outdir=', 'tmpdir=', 'preserve', 'searchruns=')) for (opt, val) in optlist: if opt == '-h' or opt == '--help': usage(0) elif opt == '-o' or opt == '--outdir': config.outdir = val elif opt == '-t' or opt == '--tmpdir': config.tmpdir = val elif opt == '-p' or opt == '--preserve': config.preserve = True elif opt == '--searchruns': config.searchruns = int(val) else: print("Unknown option %r" % opt) usage(1) except getopt.GetoptError, e: print("Bad options: %r" % str(e)) usage(1) if len(argv) != 1: print("Wrong number of arguments") usage(1) return config xappy-0.5/perftest/perftest.py0000755000175000017500000003332510703210275016401 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""perftest.py: Perform automated performance tests. This script performs automated performance tests of the Xappy module. First, it downloads sample data to use for the performance tests, if such data isn't already downloaded. Next, it performs some timed indexing runs, producing CSV log files and graphs of the performance of these runs. Next, it performs some timed search runs, producing CSV log files and graphs of the performance of these runs. FIXME - needs to have support for clearing the cache between runs (but also do some hot-cache runs): To clear the cache: 1. If /proc/sys/vm/drop_caches exists, and is writable, writing "1" to it clears the cache. 2. Otherwise, creates a large file containing random data, read all the data from it, and then delete it. """ import getopt import os import os.path import shutil import sys import time import urllib import setuppaths import indexer import searcher try: import analyse_indexlogs import analyse_searchlogs except ImportError: analyse_indexlogs = None analyse_searchlogs = None class Config(object): def __init__(self, **kwargs): for key, val in kwargs.iteritems(): setattr(self, key, val) def usage(exitval): print("Usage: perftest.py [options]") print("Options are:") print(" --help: Get help message") print(" --outdir: Set output directory") print(" --tmpdir: Set temporary directory") print(" --preserve: Preserve existing runs") print(" --searchruns: How many times to repeat each search run") print(" --usedb: Use a particular existing database (only do search tests)") sys.exit(exitval) def parse_argv(argv, **defaults): config = Config(**defaults) try: optlist, argv = getopt.gnu_getopt(argv, 'ho:t:p', ('help', 'outdir=', 'tmpdir=', 'preserve', 'searchruns=', 'usedb=')) for (opt, val) in optlist: if opt == '-h' or opt == '--help': usage(0) elif opt == '-o' or opt == '--outdir': config.outdir = val elif opt == '-t' or opt == '--tmpdir': config.tmpdir = val elif opt == '-p' or opt == '--preserve': config.preserve = True elif opt == '--searchruns': config.searchruns = int(val) elif opt == '--usedb': config.usedb = val else: print("Unknown option %r" % opt) usage(1) except getopt.GetoptError, e: print("Bad options: %r" % str(e)) usage(1) if len(argv) != 1: print("Wrong number of arguments") usage(1) return config def do_index(config, testrun): dbpath = testrun.dbpath(config) indexlogpath = testrun.indexlogpath(config) if not config.preserve or \ not os.path.exists(dbpath) or \ not os.path.exists(indexlogpath): if os.path.exists(dbpath): shutil.rmtree(dbpath) if os.path.exists(indexlogpath): os.unlink(indexlogpath) print "Starting index run (creating %s)" % dbpath indexer.index_file(inputfile=testrun.inputfile, dbpath=dbpath, logpath=indexlogpath, flushspeed=testrun.flushspeed, description=testrun.description, maxdocs=testrun.maxdocs, logspeed=testrun.logspeed) print "Ending index run" def do_search(config, testrun): dbpath = testrun.dbpath(config) # FIXME - clear cache before first run for runnum in range(1, config.searchruns + 1): for queryfile, concurrency, extraargs in testrun.queryruns: searchlogfile = testrun.searchlogpath(config, queryfile, concurrency, extraargs, runnum) if config.preserve and \ os.path.exists(searchlogfile): continue print "Starting search run (logging to %s)" % searchlogfile tests = searcher.QueryTests(queryfile, dbpath, searchlogfile, concurrency, **extraargs) tests.run() print "Ending search run" def analyse_index(config): if analyse_indexlogs is None: return alltimes = {} for testrun in config.testruns: if testrun.noindex: continue indexlogpath = testrun.indexlogpath(config) outprefix = testrun.indexoutprefix(config) desc_line, times = analyse_indexlogs.parse_logfile(indexlogpath) title_line = testrun.description if testrun.maxdocs is not None: title_line += ", maxdocs=%d" % testrun.maxdocs title_line += ", flush=%d" % testrun.flushspeed filenameprefix = testrun.filename_safe_description() + testrun.maxdocs_pathbit() analyse_indexlogs.generate_figures(times, outprefix, title_line) if filenameprefix not in alltimes: alltimes[filenameprefix] = (testrun.description, []) alltimes[filenameprefix][1].append(("flush=%d" % testrun.flushspeed, times)) for desc in alltimes.iterkeys(): outprefix = os.path.join(config.outdir, 'index_comparison_%s_' % (desc, )) analyse_indexlogs.generate_comparison_figures(alltimes[desc][1], outprefix, alltimes[desc][0]) def analyse_search(config): if analyse_searchlogs is None: return for testrun in config.testruns: for runnum in range(1, config.searchruns + 1): for queryfile, concurrency, extraargs in testrun.queryruns: searchlogpath = testrun.searchlogpath(config, queryfile, concurrency, extraargs, runnum) outprefix = testrun.searchoutprefix(config, queryfile, concurrency, extraargs, runnum) log = analyse_searchlogs.parse_logfile(searchlogpath) title = testrun.description title += ", " + os.path.basename(queryfile) if concurrency != 1: title += ", concurrency=%d" % concurrency for arg in extraargs: if arg == 'range': title += ", range=%s,%d,%d" % extraargs[arg] elif arg == 'gettags': title += ", gettags=%s,%d" % extraargs[arg] else: title += ", %s=%s" % (arg, extraargs[arg]) analyse_searchlogs.generate_figures(log, outprefix, title) class TestRun(object): def __init__(self, inputfile, description, flushspeed=10000, maxdocs=None, logspeed=1000, noindex=False): """ - description: textual description of this run (excluding information about other parameters specified here) - flushspeed: frequency (ie, number of adds) with which to explicitly call flush() on the database. - maxdocs: maximum number of documents to add (stop automatically after this many). - logspeed: make a log entry each time we add "logspeed" documents. - noindex: If True, don't do an indexing run (use existing database) """ self.inputfile = os.path.abspath(inputfile) self.description = description self.flushspeed = flushspeed self.maxdocs = maxdocs self.logspeed = logspeed self.noindex = noindex self.queryruns = [] def add_query_run(self, queryfile, concurrency, **extraargs): self.queryruns.append((os.path.abspath(queryfile), concurrency, extraargs)) def maxdocs_pathbit(self): if self.maxdocs is None: return '' return "_maxdocs%d" % self.maxdocs def _flushspeed_pathbit(self): return "_flush%d" % self.flushspeed def _index_pathbit(self): return "%s%s%s" % (self.filename_safe_description(), self._flushspeed_pathbit(), self.maxdocs_pathbit()) def _filename_safe_path(self, path): desc = [] for char in path.lower(): if char.isalnum(): desc.append(char) elif len(desc) > 0 and desc[-1] != '_': desc.append('_') return ''.join(desc) def filename_safe_description(self): return self._filename_safe_path(self.description) def dbpath(self, config): if self.noindex: return self.inputfile return os.path.join(config.tmpdir, 'db_%s' % self._index_pathbit()) def indexlogpath(self, config): return os.path.join(config.outdir, 'indexlog_%s.csv' % self._index_pathbit()) def indexoutprefix(self, config): return os.path.join(config.outdir, 'index_%s_' % self._index_pathbit()) def extraargs_pathbit(self, extraargs): extraargs_list = list(extraargs.iteritems()) extraargs_list.sort() extraargs = [] for key, val in extraargs_list: extraargs.append(key + "_" + str(val)) extraargs = '_'.join(extraargs) extraargs = self._filename_safe_path(extraargs) while extraargs.endswith('_'): extraargs = extraargs[:-1] if extraargs == '': return '' return "_" + extraargs def queryfile_pathbit(self, queryfile): return self._filename_safe_path(os.path.splitext(os.path.basename(queryfile))[0]) def searchlogpath(self, config, queryfile, concurrency, extraargs, runnum): return os.path.join(config.outdir, 'searchlog_%s_%s_threads%d%s_run%d.csv' % (self._index_pathbit(), self.queryfile_pathbit(queryfile), concurrency, self.extraargs_pathbit(extraargs), runnum)) def searchoutprefix(self, config, queryfile, concurrency, extraargs, runnum): return os.path.join(config.outdir, 'search_%s_%s_threads%d%s_run%d_' % (self._index_pathbit(), self.queryfile_pathbit(queryfile), concurrency, self.extraargs_pathbit(extraargs), runnum)) def searchdumpdir(self, config, queryfile, concurrency, extraargs, runnum): return os.path.join(config.tmpdir, 'searchdump_%s_%s_threads%d%s_run%d' % (self._index_pathbit(), self.queryfile_pathbit(queryfile), concurrency, self.extraargs_pathbit(extraargs), runnum)) if __name__ == '__main__': config = parse_argv(sys.argv, tmpdir='perftesttmpdir', outdir='perftestoutdir', preserve=False, searchruns=5, usedb=None) for key in ('tmpdir', 'outdir', ): setattr(config, key, os.path.abspath(getattr(config, key))) # Build up a set of test runs to do. config.testruns = [] # Comment out the index runs with different flush values for now. if False: testrun = TestRun("sampledata/wikipedia.dump", "wikipedia", flushspeed=1, maxdocs=1000, logspeed=10) config.testruns.append(testrun) testrun = TestRun("sampledata/wikipedia.dump", "wikipedia", flushspeed=10, maxdocs=1000, logspeed=10) config.testruns.append(testrun) testrun = TestRun("sampledata/wikipedia.dump", "wikipedia", 1000, maxdocs=10000) config.testruns.append(testrun) testrun = TestRun("sampledata/wikipedia.dump", "wikipedia", 10000) config.testruns.append(testrun) if config.usedb is None: testrun = TestRun("sampledata/wikipedia.dump", "wikipedia", 100000) else: testrun = TestRun(config.usedb, "wikipedia", noindex=True) testrun.add_query_run("sampledata/queries.txt", 1) testrun.add_query_run("sampledata/queries.txt", 1, use_or=True) testrun.add_query_run("sampledata/queries.txt", 10) testrun.add_query_run("sampledata/queries.txt", 100) testrun.add_query_run("sampledata/queries.txt", 1, sort="doclen") testrun.add_query_run("sampledata/queries.txt", 1, collapse="doclen") testrun.add_query_run("sampledata/queries.txt", 1, range=("doclen", 10000, 30000)) #testrun.add_query_run("sampledata/queries.txt", 1, getfacets=10) #testrun.add_query_run("sampledata/queries.txt", 1, gettags=("tags",10)) config.testruns.append(testrun) # Make directories (and ensure they're empty) if not config.preserve: if os.path.exists(config.outdir): shutil.rmtree(config.outdir) if os.path.exists(config.tmpdir): shutil.rmtree(config.tmpdir) if not os.path.exists(config.outdir): os.mkdir(config.outdir) if not os.path.exists(config.tmpdir): os.mkdir(config.tmpdir) # Do the indexing for testrun in config.testruns: if not testrun.noindex: do_index(config, testrun) analyse_index(config) # Do the searching for testrun in config.testruns: do_search(config, testrun) analyse_search(config) xappy-0.5/perftest/searcher.py0000755000175000017500000001140610703015433016334 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os import sys import time import thread import threading import getopt import xappy class TestRunner(threading.Thread): def __init__(self, tests, num): threading.Thread.__init__(self) self.tests = tests self.num = num self.sconn = xappy.SearchConnection(tests.dbdir) def run(self): try: while True: querynum, query = self.tests.get_query() query = query.strip() querystart = time.time() if self.tests.use_or: parsedquery = self.sconn.query_parse(query, default_op=self.sconn.OP_OR) else: parsedquery = self.sconn.query_parse(query) if self.tests.range is not None: rangequery = self.sconn.query_range(*self.tests.range) parsedquery = self.sconn.query_filter(parsedquery, rangequery) search_getfacets = (self.tests.getfacets is not None) search_gettags = None if self.tests.gettags is not None: self.search_gettags = self.tests.gettags[0] results = self.sconn.search(parsedquery, 0, 10, sortby=self.tests.sort, collapse=self.tests.collapse, getfacets=search_getfacets, gettags=search_gettags) self.tests.log_search(self.num, querynum, results.matches_estimated, querystart, parsedquery.get_length(), query) except StopIteration: return class QueryTests(object): def __init__(self, queryfile=None, dbdir=None, logfile=None, threads=1, sort=None, collapse=None, range=None, getfacets=None, gettags=None, use_or=False): self.queryfile = queryfile self.dbdir = dbdir self.logfile = logfile self.qfd = open(queryfile) self.logfd = open(logfile, "a") self.logfd.write("Thread Num,Query Num,Count of queries with some matches,Estimated matches,Time (seconds),Elapsed Time(seconds)\n") self.querycount = 0 self.matchingcount = 0 self.starttime = time.time() self.threads = threads self.use_or = use_or self.sort = sort self.collapse = collapse self.range = range self.getfacets = getfacets self.gettags = gettags self.mutex = threading.Lock() def get_query(self): self.mutex.acquire() try: q = self.qfd.readline() if len(q) == 0: raise StopIteration self.querycount += 1 return self.querycount, q finally: self.mutex.release() def log_search(self, threadnum, querynum, resultest, querystart, querylen, query): self.mutex.acquire() try: try: if resultest != 0: self.matchingcount += 1 currtime = time.time() self.logfd.write("%d,%d,%d,%d,%f,%f,%d,%r\n" % (threadnum, querynum, self.matchingcount, resultest, currtime - querystart, currtime - self.starttime, querylen, query)) self.logfd.flush() except StopIteration: return finally: self.mutex.release() def run(self): for i in xrange(self.threads): runner = TestRunner(self, i + 1) runner.start() runner.join() xappy-0.5/perftest/setuppaths.py0000644000175000017500000000267010702510046016737 0ustar richardrichard# Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""setuppaths.py: Setup sys.path This is a special module which ensures that sys.path is set appropriately simply by being imported. To use, simply import it at the very start of any module which requires use of xappy. This will allow the module to work with an uninstalled version of xappy located relative to this path. """ __docformat__ = "restructuredtext en" import os import sys def setup_path(): """Set up sys.path to allow us to import Xappy when run uninstalled. """ abspath = os.path.abspath(__file__) dirname = os.path.dirname(abspath) dirname = os.path.dirname(dirname) if os.path.exists(os.path.join(dirname, 'xappy')): sys.path.insert(0, dirname) setup_path() xappy-0.5/secore/0000755000175000017500000000000011005556727013621 5ustar richardrichardxappy-0.5/secore/__init__.py0000644000175000017500000000231310667533120015724 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. Xappy used to be called "secore". To assist in migration to secore, this simple compatibility wrapper is provided, which allows existing code which use: >>> import secore to work without changes. References to the "secore" name should be changed to "xappy" whenever possible, however, since this compatibility wrapper will be removed at some point. """ __docformat__ = "restructuredtext en" from xappy import * xappy-0.5/secore/datastructures.py0000644000175000017500000000152110667533345017253 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.datastructures import * xappy-0.5/secore/errors.py0000644000175000017500000000151110667533467015516 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.errors import * xappy-0.5/secore/fieldactions.py0000644000175000017500000000151710667533503016643 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.fieldactions import * xappy-0.5/secore/fieldmappings.py0000644000175000017500000000152010667533512017013 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.fieldmappings import * xappy-0.5/secore/highlight.py0000644000175000017500000000151410667533525016147 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.highlight import * xappy-0.5/secore/indexerconnection.py0000644000175000017500000000152410667533534017717 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.indexerconnection import * xappy-0.5/secore/marshall.py0000644000175000017500000000151310667533543016002 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.marshall import * xappy-0.5/secore/parsedate.py0000644000175000017500000000151410667533551016147 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.parsedate import * xappy-0.5/secore/searchconnection.py0000644000175000017500000000152310667533565017531 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Compatibility wrapper for Xappy. """ from xappy.searchconnection import * xappy-0.5/testdata/0000755000175000017500000000000011005556727014152 5ustar richardrichardxappy-0.5/testdata/query_sourcewords.txt0000644000175000017500000362451310667526240020535 0ustar richardrichardA A's Advent Advent's Advents Africa Africa's African Africans Allah Allah's America America's American Americana Americana's Americanism Americanism's Americanisms Americans Anglican Anglicans Anglo Anglo's Anglos Antarctic Antarctic's Antarctica Antarctica's Apr Apr's April April's Aprils Aquarius Aquarius's Aquariuses Arab Arab's Arabic Arabic's Arabs Arctic Arctic's Aries Arieses As Asia Asia's Asian Asians AstroTurf AstroTurfs Atlantic Atlantic's Aug Aug's August August's Augusts Australia Australia's Australian Australian's Australians Ave Ave's Aves B B's Baptist Baptist's Baptists Bible Bible's Bibles Black Black's Blacks Blvd Braille Braille's Brailled Brailles Brailling Britain Britain's British Britisher Brown Brown's Brownie Brownie's Brownies Buddha Buddha's Buddhas Buddhism Buddhism's Buddhisms Buddhist Buddhist's Buddhists C C's Cabinet Cabinets Canadian Canadians Cancer Cancer's Cancers Cantonese Cantonese's Capitol Capitol's Capitols Capricorn Capricorn's Capricorns Caribbean Caribbeans Catholic Catholicism Catholicism's Catholicisms Catholics Caucasian Caucasians Celsius Celsiuses Chicano Chicano's Chicanos Chinatown Chinatown's Chinatowns Chinese Christ Christ's Christian Christian's Christianities Christianity Christianity's Christians Christmas Christmas's Christmases Christs Ci Co Co's Coke Coke's Cokes Communion Communion's Communions Confederacy Confederacy's Confederate Confederates Congress Congress's Congresses Constitution Cs Cyrillic D D's Dalmatian Dalmatian's Dalmatians Danish Dec Dec's December December's Decembers Democrat Democrat's Democratic Democrats Dixie Dixie's Doctor Dr Dr's Dumpster Dumpsters Dutch Dutch's E E's Earth Easter Easter's Easters Emmies Emmy Emmy's Emmys England England's English English's Englished Englisher Englishes Englishing Episcopalian Episcopalians Es Eskimo Eskimo's Eskimos Europe Europe's European Europeans F F's Fahrenheit Fahrenheits Father Father's Fathers Feb Feb's Februaries February February's Februarys Fed Fed's Feds French French's Frenched Frenches Frenching Freudian Freudians Fri Fri's Friday Friday's Fridays Frisbee Frisbee's Frisbees G G's Gemini Gemini's Geminis Gen Gen's German German's Germans God God's Gospel Gospel's Gospels Grammies Grammy Greek Greek's Greeks H H's Halloween Halloween's Halloweens Hanukkah Hanukkah's Hanukkahs Hebrew Hebrew's Hebrews Highness Highness's Hindu Hindu's Hinduism Hinduism's Hinduisms Hindus Hispanic Hispanics Hollywood Hollywood's Holocaust House House's I I'd I'll I'm I've Inc Inc's Indian Indian's Indians Internet Inuit Inuit's Inuits Irish Irisher Islam Islam's Islamic Islamics Islams Italian Italian's Italians J J's Jacuzzi Jacuzzis Jan Jan's Januaries January January's Januarys Japanese Japaneses Jeep Jeeps Jesus Jew Jew's Jewish Jews John John's Jr Jr's Judaism Judaism's Judaisms Jul Jul's Julies July July's Jun Jun's June June's Junes Junior Juniors Jupiter Jupiter's K K's Kleenex Kleenex's Kleenexes Koran Koran's Korans Korean Koreans Kwanzaa Kwanzaas L L's Latin Latin's Latina Latina's Latinas Latiner Latino Latinos Latins Laundromat Laundromat's Laundromats Lent Lent's Lents Leo Leo's Leos Libra Libra's Libras Ln Lord Lord's Lords Lutheran Lutheran's Lutherans M M's Mace Mace's Maced Maces Macing Mafia Mafia's Mafias Mandarin Maori Maori's Maoris Mar Mar's March March's Marches Marine Marines Mars Martian Martians Marxism Marxism's Marxisms Marxist Marxist's Marxists Mason Mason's Masons Mass Masses May May's Mays McCoy McCoy's McCoys Mecca Mecca's Meccas Medicaid Medicaid's Medicaids Medicare Medicare's Medicares Mediterranean Mediterranean's Mediterraneans Mercuries Mercury Mercury's Messiah Messiah's Messiahs Messrs Messrs's Methodist Methodist's Methodists Mexican Mexicans Midwest Midwest's Midwestern Miss Miss's Misses Mister Mister's Mon Mon's Monday Monday's Mondays Mons Mormon Mormon's Mormons Moslem Moslem's Moslems Mount Mount's Mr Mr's Mrs Ms Mt Mt's Muhammad Muhammad's Muslim Muslim's Muslims Muzak Muzak's Muzaks N N's Nazi Nazi's Nazis Negro Negro's Negroes Neptune Neptune's Nov Nov's November November's Novembers O OK OKs Oct Oct's October October's Octobers Olympic Olympics Orient Orient's Oriental Orientals Orients Os Oscar Oscar's Oscars P P's Pacific Pacific's Passover Passover's Passovers Pentagon Pentagon's Pharaoh Pharaoh's Pharaohs Pilgrim Pilgrims Pisces Pisces's Pkwy Pl Plexiglas Plexiglas's Plexiglases Pluto Pluto's Polaroid Polaroid's Polaroids Pole Pole's Poles Polish Pope Pope's Popes Popsicle Popsicle's Popsicles Portuguese Portuguese's Presbyterian Presbyterians President Presidents Prof Prohibition Prohibition's Prohibitions Protestant Protestant's Protestants Puritan Puritan's Puritans Pyrex Pyrex's Pyrexes Q Q's R R's Ramadan Ramadan's Ramadans Rd Rd's Realtor Realtors Renaissance Renaissance's Renaissances Rep Rep's Representative Representatives Republican Republicans Resurrection Resurrection's Resurrections Rev Rev's Reverend Rollerblade Rollerblades Roman Romans Rte Russian Russian's Russians S S's Sabbath Sabbath's Sabbaths Sagittarius Sagittarius's Sagittariuses Santa Santa's Sat Sat's Satan Satan's Saturday Saturday's Saturdays Saturn Saturn's Savior Savior's Scandinavia Scandinavia's Scandinavian Scandinavians Scorpio Scorpio's Scorpios Scotch Scotches Scottish Scripture Scripture's Scriptures Sec Secretaries Secretary Sen Senate Senate's Senates Senator Senior Seniors Sept Sept's September September's Septembers Sgt Sikh Sikh's Sikhism Sikhism's Sikhisms Sikhs Sister Sisters Soviet Soviets Spanish Spanish's Spartan Spartans Sq Sq's Sr St St's Styrofoam Styrofoams Sun Sunday Sunday's Sundays Swiss Swisses T T's Taiwanese Talmud Talmud's Talmuds Taurus Taurus's Tauruses Teflon Teflon's Teflons Terr Terr's Thanksgiving Thanksgivings Thermos Thermos's Thermoses Thurs Thursday Thursday's Thursdays Trinities Trinity Trinity's Tues Tuesday Tuesday's Tuesdays Tylenol U Uranus Uranus's V V's Velcro Velcro's Velcros Venus Venuses Virgo Virgo's Virgos W W's Walkman Walkmans Wed Wed's Wednesday Wednesday's Wednesdays Welsh Western Westerner Westerners Westerns White White's Whites X X's Xerox Xerox's Xeroxed Xeroxes Xeroxing Xmas Xmas's Xmases Y Y's Yank Yank's Yankee Yankee's Yankees Yanks Yiddish Yiddish's Yuletide Yuletides Z Z's a aardvark aardvark's abaci aback abacus abacus's abacuses abandon abandoned abandoning abandonment abandonment's abandons abash abashed abashes abashing abate abated abates abating abbey abbey's abbeys abbot abbot's abbots abbreviate abbreviated abbreviates abbreviating abbreviation abbreviation's abbreviations abdicate abdicated abdicates abdicating abdication abdication's abdications abdomen abdomen's abdomens abdominal abduct abducted abducting abduction abduction's abductions abducts aberration aberration's aberrations abet abets abetted abetting abhor abhorred abhorrence abhorrence's abhorrent abhorring abhors abide abided abides abiding abidings abilities ability ability's abject abjected abjecting abjects ablaze able abler ables ablest ably abnormal abnormalities abnormality abnormality's abnormally aboard abode abode's aboded abodes aboding abolish abolished abolishes abolishing abolition abolition's abolitionist abolitionist's abolitionists abominable abomination abomination's aboriginal aboriginals aborigine aborigine's aborigines abort aborted aborting abortion abortion's abortions abortive aborts abound abounded abounding abounds about abouts above aboveboard abrasive abrasive's abrasively abrasives abreast abridge abridged abridgement abridgement's abridgements abridges abridging abroad abrupt abrupter abruptest abruptly abruptness abruptness's abscess abscess's abscessed abscesses abscessing abscond absconded absconding absconds absence absence's absences absent absented absentee absentee's absenteeism absenteeism's absentees absenting absently absents absolute absolutely absoluter absolutes absolutest absolve absolved absolves absolving absorb absorbed absorbent absorbents absorbing absorbs absorption absorption's abstain abstained abstaining abstains abstention abstention's abstentions abstinence abstinence's abstinent abstract abstracted abstracter abstractest abstracting abstraction abstraction's abstractions abstracts abstruse absurd absurder absurdest absurdities absurdity absurdity's absurdly abundance abundance's abundances abundant abundantly abuse abused abuser abusers abuses abusing abusive abysmal abysmally abyss abyss's abysses academic academically academics academies academy academy's accede acceded accedes acceding accelerate accelerated accelerates accelerating acceleration acceleration's accelerations accelerator accelerator's accelerators accent accent's accented accenting accents accentuate accentuated accentuates accentuating accept acceptability acceptability's acceptable acceptably acceptance acceptance's acceptances accepted accepting accepts access access's accessed accesses accessibility accessibility's accessible accessing accessories accessory accessory's accident accident's accidental accidentally accidentals accidents acclaim acclaimed acclaiming acclaims acclimate acclimated acclimates acclimating acclimation acclimation's acclimatize acclimatized acclimatizes acclimatizing accolade accolade's accoladed accolades accolading accommodate accommodated accommodates accommodating accommodation accommodation's accommodations accompanied accompanies accompaniment accompaniment's accompaniments accompanist accompanist's accompanists accompany accompanying accomplice accomplice's accomplices accomplish accomplished accomplishes accomplishing accomplishment accomplishment's accomplishments accord accord's accordance accordance's accorded according accordingly accordion accordion's accordions accords accost accosted accosting accosts account account's accountability accountability's accountable accountancy accountancy's accountant accountant's accountants accounted accounting accounting's accounts accredit accreditation accreditation's accredited accrediting accredits accrue accrued accrues accruing accumulate accumulated accumulates accumulating accumulation accumulation's accumulations accuracy accuracy's accurate accurately accusation accusation's accusations accuse accused accused's accuser accuser's accusers accuses accusing accusingly accustom accustomed accustoming accustoms ace ace's aced acerbic aces ache ached aches achier achiest achievable achieve achieved achievement achievement's achievements achiever achiever's achievers achieves achieving aching achy acid acid's acidic acidity acidity's acids acing acknowledge acknowledged acknowledgement acknowledgement's acknowledgements acknowledges acknowledging acne acne's acorn acorn's acorns acoustic acoustics acoustics's acquaint acquaintance acquaintance's acquaintances acquainted acquainting acquaints acquiesce acquiesced acquiescence acquiescence's acquiesces acquiescing acquire acquired acquires acquiring acquisition acquisition's acquisitions acquit acquited acquiting acquits acquittal acquittal's acquittals acquitted acquitting acre acre's acreage acreage's acreages acres acrid acrider acridest acrimonious acrimony acrimony's acrobat acrobat's acrobatic acrobatics acrobatics's acrobats acronym acronym's acronyms across acrylic acrylics act act's acted acting action action's actioned actioning actions activate activated activates activating activation activation's active actively actives activism activism's activist activist's activists activities activity activity's actor actor's actors actress actress's actresses acts actual actualisation actualisation's actualities actuality actuality's actually actuary actuary's acumen acumen's acupuncture acupuncture's acute acutely acuter acutes acutest ad ad's adage adage's adages adamant adamantly adapt adaptable adaptation adaptation's adaptations adapted adapting adaptive adaptor adaptor's adaptors adapts add added addendum addendum's addict addicted addicting addiction addiction's addictions addictive addicts adding addition addition's additional additionally additions additive additives address address's addressed addressee addressee's addressees addresses addressing adds adept adepter adeptest adeptly adepts adequacy adequacy's adequate adequately adhere adhered adherence adherence's adherent adherent's adherents adheres adhering adhesion adhesion's adhesive adhesives adjacent adjectival adjective adjective's adjectives adjoin adjoined adjoining adjoins adjourn adjourned adjourning adjournment adjournment's adjournments adjourns adjudicate adjudicated adjudicates adjudicating adjudicator adjudicator's adjudicators adjunct adjunct's adjuncts adjust adjustable adjusted adjusting adjustment adjustment's adjustments adjusts administer administered administering administers administration administration's administrations administrative administrator administrator's administrators admirable admirably admiral admiral's admirals admiration admiration's admire admired admirer admirer's admirers admires admiring admiringly admissible admission admission's admissions admit admits admittance admittance's admitted admittedly admitting admonish admonished admonishes admonishing admonition admonition's admonitions ado ado's adobe adobe's adobes adolescence adolescence's adolescences adolescent adolescents adopt adopted adopting adoption adoption's adoptions adoptive adopts adorable adoration adoration's adore adored adores adoring adorn adorned adorning adornment adornment's adornments adorns adrenaline adrenaline's adrift adroit adroiter adroitest adroitly ads adulation adulation's adult adulterate adulterated adulterates adulterating adulteration adulteration's adulteries adultery adultery's adulthood adulthood's adults advance advanced advancement advancement's advancements advances advancing advantage advantage's advantaged advantageous advantages advantaging advent advent's advents adventure adventure's adventured adventurer adventurer's adventurers adventures adventuring adventurous adverb adverb's adverbial adverbial's adverbials adverbs adversaries adversary adversary's adverse adversely adverser adversest adversities adversity adversity's advert advertise advertised advertisement advertisement's advertisements advertiser advertiser's advertisers advertises advertising advertising's adverts advice advice's advisable advise advised adviser adviser's advisers advises advising advisor advisories advisors advisory advocacy advocacy's advocate advocated advocates advocating aerial aerials aerobic aerobics aerodynamic aerodynamics aerodynamics's aeroplane aeroplane's aeroplanes aerosol aerosol's aerosols aerospace aerospace's aesthetic aesthetically aesthetics aesthetics's afar affable affabler affablest affably affair affair's affairs affect affectation affectation's affectations affected affecting affection affection's affectionate affectionately affectioned affectioning affections affects affidavit affidavit's affidavits affiliate affiliated affiliates affiliating affiliation affiliation's affiliations affinities affinity affinity's affirm affirmation affirmation's affirmations affirmative affirmatively affirmatives affirmed affirming affirms affix affixed affixes affixing afflict afflicted afflicting affliction affliction's afflictions afflicts affluence affluence's affluent afford affordable afforded affording affords affront affront's affronted affronting affronts afield aflame afloat afoot aforementioned aforesaid afraid afresh after aftereffect aftereffect's aftereffects afterlife afterlife's afterlives aftermath aftermath's aftermaths afternoon afternoon's afternoons afters aftershave aftershaves aftershock aftershock's aftershocks afterthought afterthought's afterthoughts afterwards again against age age's aged ageing ageings agencies agency agency's agenda agenda's agendas agent agent's agents ages aggravate aggravated aggravates aggravating aggravation aggravation's aggravations aggregate aggregated aggregates aggregating aggression aggression's aggressive aggressively aggressiveness aggressor aggressor's aggressors aggrieve aggrieved aggrieves aggrieving aghast agile agiler agilest agility agility's agitate agitated agitates agitating agitation agitation's agitations agitator agitator's agitators aglow agnostic agnostic's agnosticism agnosticism's agnostics ago agonies agonise agonised agonises agonising agonisingly agony agony's agree agreeable agreeably agreed agreeing agreement agreement's agreements agrees agricultural agriculture agriculture's aground ah aha ahas ahead ahoy ahoys aid aide aide's aided aides aiding aids ail ailed ailing ailment ailment's ailments ails aim aimed aiming aimless aimlessly aims ain't air air's airborne aircraft aircraft's aired airfare airfares airfield airfield's airfields airier airiest airily airing airing's airings airless airline airline's airliner airliner's airliners airlines airmail airmailed airmailing airmails airport airport's airports airs airspace airspace's airstrip airstrip's airstrips airtight airwaves airy aisle aisle's aisled aisles aisling ajar akin alarm alarmed alarming alarmingly alarmist alarmist's alarmists alarms alas alases albeit albino albino's albinos album album's albums alcohol alcohol's alcoholic alcoholic's alcoholics alcoholism alcoholism's alcohols alcove alcove's alcoves alderman alderman's aldermen alderwoman alderwomen ale ale's alert alerted alerter alertest alerting alerts ales alfalfa alfalfa's alga algae algebra algebra's algebraic algorithm algorithm's algorithms alias aliased aliases aliasing alibi alibi's alibied alibiing alibis alien alien's alienate alienated alienates alienating alienation alienation's aliened aliening aliens alight alighted alighting alights align aligned aligning alignment alignment's alignments aligns alike alimony alimony's alit alive alkali alkali's alkalies alkaline alkalis all allay allayed allaying allays allegation allegation's allegations allege alleged allegedly alleges allegiance allegiance's allegiances alleging allegorical allegories allegory allegory's allergic allergies allergy allergy's alleviate alleviated alleviates alleviating alleviation alleviation's alley alley's alleys alliance alliance's alliances allied allies allies's alligator alligator's alligators allocate allocated allocates allocating allocation allocation's allocations allot allotment allotment's allotments allots allotted allotting allow allowable allowance allowance's allowances allowed allowing allows alloy alloy's alloyed alloying alloys allude alluded alludes alluding allure allured allures alluring allusion allusion's allusions ally allying almanac almanac's almanacs almighty almond almond's almonds almost alms aloft aloha aloha's alohas alone along alongside aloof aloud alpha alpha's alphabet alphabet's alphabeted alphabetic alphabetical alphabetically alphabeting alphabets alphanumeric alpine alpines already alright also altar altar's altars alter alterable alteration alteration's alterations altercation altercation's altercations altered altering alternate alternated alternately alternates alternating alternation alternation's alternations alternative alternative's alternatively alternatives alternator alternator's alters although altitude altitude's altitudes alto alto's altogether altos altruism altruism's altruistic aluminium aluminium's alumna alumna's alumnae alumni alumnus alumnus's always am amalgamate amalgamated amalgamates amalgamating amalgamation amalgamation's amalgamations amass amassed amasses amassing amateur amateur's amateurish amateurs amaze amazed amazement amazement's amazes amazing amazingly ambassador ambassador's ambassadorial ambassadors amber amber's ambiance ambiance's ambiances ambidextrous ambience ambience's ambiences ambient ambiguities ambiguity ambiguity's ambiguous ambiguously ambition ambition's ambitions ambitious ambitiously ambivalence ambivalence's ambivalent amble ambled ambles ambling ambulance ambulance's ambulances ambush ambush's ambushed ambushes ambushing ameba ameba's amebae amebas ameliorate ameliorated ameliorates ameliorating amelioration amelioration's amen amenable amend amended amending amendment amendment's amendments amends amends's amened amening amenities amenity amenity's amens amethyst amethyst's amethysts amiable amiably amicable amicably amid amids amidst amiss ammo ammo's ammonia ammonia's ammunition ammunition's amnesia amnesia's amnesiac amnesiac's amnesiacs amnestied amnesties amnesty amnesty's amnestying amoeba amoeba's amoebae amoebas amok amok's among amongst amoral amorous amorphous amount amount's amounted amounting amounts amp amp's amped ampere ampere's amperes ampersand ampersand's ampersands amphetamine amphetamine's amphetamines amphibian amphibian's amphibians amphibious amphitheatre amphitheatre's amphitheatres amping ample ampler amplest amplification amplification's amplifications amplified amplifier amplifier's amplifiers amplifies amplify amplifying amplitude amplitude's amply amps amputate amputated amputates amputating amputation amputation's amputations amputee amputee's amputees amuck amuck's amulet amulet's amulets amuse amused amusement amusement's amusements amuses amusing amusingly an anachronism anachronism's anachronisms anachronistic anaemia anaemia's anaemic anaesthesia anaesthesia's anaesthesiologist anaesthesiologist's anaesthesiologists anaesthetic anaesthetic's anaesthetics anaesthetise anaesthetised anaesthetises anaesthetising anaesthetist anaesthetist's anaesthetists anaesthetize anaesthetized anaesthetizes anaesthetizing anagram anagram's anagrams anal analgesic analgesics analogies analogous analogue analogue's analogy analogy's analyse analysed analyser analyser's analyses analysing analysis analysis's analyst analyst's analysts analytic analytical analytics anarchic anarchism anarchism's anarchist anarchist's anarchists anarchy anarchy's anathema anathema's anatomical anatomies anatomy anatomy's ancestor ancestor's ancestored ancestoring ancestors ancestral ancestries ancestry ancestry's anchor anchor's anchorage anchorage's anchorages anchored anchoring anchorman anchorman's anchormen anchors anchorwoman anchorwomen anchovies anchovy anchovy's ancient ancienter ancientest ancients and android android's androids ands anecdota anecdotal anecdote anecdote's anecdotes anew angel angel's angelic angelically angels anger anger's angered angering angers angle angle's angled angler angler's anglers angles angling angling's angrier angriest angrily angry angst angst's anguish anguish's anguished anguishes anguishing angular ani animal animal's animals animate animated animates animating animation animation's animations animosities animosity animosity's ankle ankle's ankled ankles ankling annals annex annexation annexation's annexations annexe annexed annexes annexing annihilate annihilated annihilates annihilating annihilation annihilation's anniversaries anniversary anniversary's annotate annotated annotates annotating annotation annotation's annotations announce announced announcement announcement's announcements announcer announcer's announcers announces announcing annoy annoyance annoyance's annoyances annoyed annoying annoyingly annoys annual annually annuals annuities annuity annuity's annul annulled annulling annulment annulment's annulments annuls anoint anointed anointing anoints anomalies anomalous anomaly anomaly's anon anonymity anonymity's anonymous anonymously anorak anoraks anorexia anorexia's anorexic anorexics another answer answer's answerable answered answering answers ant ant's antacid antacid's antacids antagonise antagonised antagonises antagonising antagonism antagonism's antagonisms antagonist antagonist's antagonistic antagonistically antagonists ante ante's anteater anteater's anteaters antebellum anted anteed anteing antelope antelope's antelopes antenna antenna's antennae antennas antes anthem anthem's anthems anthill anthills anthologies anthology anthology's anthrax anthrax's anthropological anthropologist anthropologist's anthropologists anthropology anthropology's antibiotic antibiotic's antibiotics antibodies antibody antibody's antic anticipate anticipated anticipates anticipating anticipation anticipation's anticipations anticlimactic anticlimax anticlimax's anticlimaxes antics antidote antidote's antidotes antifreeze antifreeze's antihistamine antihistamine's antihistamines anting antipathies antipathy antipathy's antiperspirant antiperspirant's antiperspirants antiquate antiquated antiquates antiquating antique antique's antiqued antiques antiquing antiquities antiquity antiquity's antiseptic antiseptics antisocial antitheses antithesis antithesis's antitrust antitrust's antler antler's antlers antonym antonym's antonyms ants anus anus's anuses anvil anvil's anvilled anvilling anvils anxieties anxiety anxiety's anxious anxiously any anybodies anybody anyhow anymore anyone anyplace anything anythings anytime anyway anyways anywhere anywheres aorta aorta's aortae aortas apart apartheid apartheid's apartment apartment's apartments apathetic apathy apathy's ape ape's aped aperitif aperitifs aperture aperture's apertures apes apex apex's apexes aphorism aphorism's aphorisms aphrodisiac aphrodisiac's aphrodisiacs apices apiece aping aplomb aplomb's apocalypse apocalypse's apocalypses apocalyptic apocryphal apolitical apologetic apologetically apologetics apologies apologise apologised apologises apologising apology apology's apoplectic apoplexies apoplexy apoplexy's apostle apostle's apostles apostolic apostrophe apostrophe's apostrophes appal appalled appalling appallingly appals apparatus apparatus's apparatuses apparel apparel's apparelled apparelling apparels apparent apparently apparition apparition's apparitions appeal appeal's appealed appealing appeals appear appearance appearance's appearances appeared appearing appears appease appeased appeasement appeasement's appeasements appeases appeasing append appendage appendage's appendages appended appendices appendicitis appendicitis's appending appendix appendix's appendixes appends appetiser appetiser's appetisers appetising appetite appetite's appetites applaud applauded applauding applauds applause applause's apple apple's apples applesauce applesauce's appliance appliance's appliances applicability applicability's applicable applicant applicant's applicants application application's applications applicator applicator's applicators applied applies apply applying appoint appointed appointee appointee's appointees appointing appointment appointment's appointments appoints apportion apportioned apportioning apportions apposite appraisal appraisal's appraisals appraise appraised appraises appraising appreciable appreciate appreciated appreciates appreciating appreciation appreciation's appreciations appreciative appreciatively apprehend apprehended apprehending apprehends apprehension apprehension's apprehensions apprehensive apprentice apprentice's apprenticed apprentices apprenticeship apprenticeship's apprenticeships apprenticing apprise apprised apprises apprising approach approachable approached approaches approaching approbation approbation's approbations appropriate appropriated appropriately appropriates appropriating appropriation appropriation's appropriations approval approval's approvals approve approved approves approving approvingly approximate approximated approximately approximates approximating approximation approximation's approximations apricot apricot's apricots apron apron's aprons apt apter aptest aptitude aptitude's aptitudes aptly aquamarine aquamarine's aquamarines aquaria aquarium aquarium's aquariums aquatic aquatics aqueduct aqueduct's aqueducts arable arbiter arbiter's arbiters arbitrarily arbitrary arbitrate arbitrated arbitrates arbitrating arbitration arbitration's arbitrator arbitrator's arbitrators arbores arbour arbour's arboures arbours arc arc's arcade arcade's arcades arcane arced arch arch's archaeological archaeologist archaeologist's archaeologists archaeology archaeology's archaic archbishop archbishop's archbishops arched archeology archer archer's archers archery archery's arches archest archetypal arching archipelago archipelago's archipelagoes archipelagos architect architect's architects architectural architecture architecture's architectures archive archive's archived archives archiving archway archway's archways arcing arcked arcking arcs arctic arctics ardent ardently ardour ardour's ardours arduous arduously are area area's areas aren't arena arena's arenas ares arguable arguably argue argued argues arguing argument argument's argumentative arguments aria aria's arias arid arider aridest arise arisen arises arising aristocracies aristocracy aristocracy's aristocrat aristocrat's aristocratic aristocrats arithmetic arithmetic's ark ark's arks arm arm's armadillo armadillo's armadillos armament armament's armaments armband armband's armbands armchair armchair's armchairs armed armful armful's armfuls armhole armhole's armholes armies arming armistice armistice's armistices armour armour's armoured armouries armouring armours armoury armoury's armpit armpit's armpits arms armsful army army's aroma aroma's aromas aromatic aromatics arose around arousal arousal's arouse aroused arouses arousing arraign arraigned arraigning arraignment arraignment's arraignments arraigns arrange arranged arrangement arrangement's arrangements arranges arranging array array's arrayed arraying arrays arrears arrest arrested arresting arrests arrival arrival's arrivals arrive arrived arrives arriving arrogance arrogance's arrogant arrogantly arrow arrow's arrows arse arse's arsehole arseholes arsenal arsenal's arsenals arsenic arsenic's arses arson arson's arsonist arsonist's arsonists art art's artefact artefacts arterial arteries artery artery's artful arthritic arthritics arthritis arthritis's artichoke artichoke's artichokes article article's articles articulate articulated articulately articulates articulating articulation articulation's articulations artifact artifact's artifacts artifice artifice's artifices artificial artificially artillery artillery's artisan artisan's artisans artist artist's artistic artistically artistry artistry's artists arts artsier artsiest artsy artwork artwork's artworks as asbestos asbestos's ascend ascendancy ascendancy's ascended ascending ascends ascension ascension's ascensions ascent ascent's ascents ascertain ascertained ascertaining ascertains ascetic ascetic's ascetics ascribe ascribed ascribes ascribing asexual ash ash's ashamed ashcan ashcan's ashed ashen ashes ashing ashore ashtray ashtray's ashtrays aside asides ask askance asked askew asking asks asleep asparagus asparagus's aspect aspect's aspects aspen aspen's aspens aspersion aspersion's aspersions asphalt asphalt's asphalted asphalting asphalts asphyxiate asphyxiated asphyxiates asphyxiating asphyxiation asphyxiation's asphyxiations aspirant aspirant's aspirants aspiration aspiration's aspirations aspire aspired aspires aspirin aspirin's aspiring aspirins ass ass's assail assailant assailant's assailants assailed assailing assails assassin assassin's assassinate assassinated assassinates assassinating assassination assassination's assassinations assassins assault assault's assaulted assaulter assaulting assaults assemble assembled assembler assembler's assemblers assembles assemblies assembling assembly assembly's assemblyman assemblyman's assemblymen assemblywoman assemblywomen assent assent's assented assenting assents assert asserted asserting assertion assertion's assertions assertive assertively assertiveness assertiveness's asserts asses assess assessed assesses assessing assessment assessment's assessments assessor assessor's assessors asset asset's assets assign assigned assigning assignment assignment's assignments assigns assimilate assimilated assimilates assimilating assimilation assimilation's assist assistance assistance's assistant assistant's assistants assisted assisting assists associate associated associates associating association association's associations associative assort assorted assorting assortment assortment's assortments assorts assume assumed assumes assuming assumption assumption's assumptions assurance assurance's assurances assure assured assuredly assureds assures assuring asterisk asterisk's asterisked asterisking asterisks asteroid asteroid's asteroids asthma asthma's asthmatic asthmatics astonish astonished astonishes astonishing astonishingly astonishment astonishment's astound astounded astounding astounds astray astride astringent astringents astrologer astrologer's astrologers astrological astrology astrology's astronaut astronaut's astronauts astronomer astronomer's astronomers astronomical astronomy astronomy's astute astutely astuter astutest asylum asylum's asylums asymmetry asymmetry's asynchronous asynchronously at ate ates atheism atheism's atheist atheist's atheistic atheists athlete athlete's athletes athletic athletics athletics's atlantes atlas atlas's atlases atmosphere atmosphere's atmospheres atmospheric atmospherics atom atom's atomic atomics atoms atone atoned atonement atonement's atones atoning atrocious atrociously atrocities atrocity atrocity's attach attach's attached attaching attachment attachment's attachments attach attachs attack attacked attacker attacker's attackers attacking attacks attain attainable attained attaining attainment attainment's attainments attains attempt attempted attempting attempts attend attendance attendance's attendances attendant attendant's attendants attended attending attends attention attention's attentions attentive attentively attest attested attesting attests attic attic's attics attire attired attires attiring attitude attitude's attitudes attorney attorney's attorneys attract attracted attracting attraction attraction's attractions attractive attractively attractiveness attractiveness's attracts attributable attribute attributed attributes attributing attribution attribution's attributions attune attuned attunes attuning auburn auburn's auction auction's auctioned auctioneer auctioneer's auctioneers auctioning auctions audacious audacity audacity's audible audibles audibly audience audience's audiences audio audio's audios audiovisual audit audit's audited auditing audition audition's auditioned auditioning auditions auditor auditor's auditoria auditorium auditorium's auditoriums auditors auditory audits augment augmented augmenting augments august auguster augustest augusts aunt aunt's aunts aura aura's aurae aural auras auspice auspices auspicious austere austerer austerest austerities austerity austerity's authentic authentically authenticate authenticated authenticates authenticating authenticity authenticity's author author's authored authoring authorisation authorisation's authorisations authorise authorised authorises authorising authoritarian authoritarians authoritative authoritatively authorities authority authority's authors authorship authorship's autistic autistics auto auto's autobiographical autobiographies autobiography autobiography's autocracies autocracy autocracy's autocrat autocrat's autocratic autocrats autoed autograph autograph's autographed autographing autographs autoing automate automated automates automatic automatically automatics automating automation automation's automobile automobile's automobiled automobiles automobiling automotive autonomous autonomously autonomy autonomy's autopsied autopsies autopsy autopsy's autopsying autos autoworker autoworkers autumn autumn's autumnal autumns auxiliaries auxiliary avail availability availability's available availed availing avails avalanche avalanche's avalanches avarice avarice's avaricious avenge avenged avenges avenging avenue avenue's avenues average average's averaged averages averaging averse aversion aversion's aversions avert averted averting averts aviation aviation's aviator aviator's aviators avid avider avidest avidly avocado avocado's avocadoes avocados avoid avoidable avoidance avoidance's avoided avoiding avoids avow avowal avowal's avowals avowed avowing avows await awaited awaiting awaits awake awaked awaken awakened awakening awakenings awakens awakes awaking award awarded awarding awards aware awareness awareness's awarer awarest awash away aways awe awe's awed awes awesome awful awfuller awfullest awfully awhile awing awkward awkwarder awkwardest awkwardly awkwardness awkwardness's awning awning's awnings awoke awoken awry axe axe's axed axes axing axiom axiom's axiomatic axiomatics axioms axis axis's axises axle axle's axles ay aye aye's ayes azalea azalea's azaleas azure azure's azures b baa baaed baaing baas babble babbled babbles babbling babe babe's babes babied babier babies babiest baboon baboon's baboons baby baby's babying babyish babysat babysit babysits babysitter babysitters babysitting bachelor bachelor's bachelors back back's backbone backbone's backbones backbreaking backdrop backdrop's backdrops backed backer backer's backers backfire backfired backfires backfiring backgammon backgammon's background background's backgrounds backhand backhand's backhanded backhanding backhands backing backing's backings backlash backlash's backlashes backlog backlog's backlogged backlogging backlogs backpack backpack's backpacked backpacker backpacker's backpackers backpacking backpacks backs backside backside's backsides backslash backspace backstage backstroke backstroke's backstroked backstrokes backstroking backtrack backtracked backtracking backtracks backup backup's backups backward backwards backwoods backyard backyard's backyards bacon bacon's bacteria bacterial bacterias bacterium bad badder baddest bade badge badge's badger badger's badgered badgering badgers badges badlands badly badminton badminton's badmouth badmouthed badmouthing badmouths badness badness's baffle baffled baffles baffling bag bag's bagel bagel's bagels baggage baggage's bagged baggie baggier baggies baggiest bagging baggy bagpipe bagpipes bags bail bail's bailed bailiff bailiff's bailiffs bailing bails bait bait's baited baiting baits bake baked baker baker's bakeries bakers bakery bakery's bakes baking balance balance's balanced balances balancing balconies balcony balcony's bald balded balder baldest balding baldness baldness's balds bale bale's baled baleful balefuller balefullest bales baling balk balked balking balks ball ball's ballad ballad's ballads ballast ballast's ballasted ballasting ballasts balled ballerina ballerina's ballerinas ballet ballet's ballets balling ballistic ballistics ballistics's balloon balloon's ballooned ballooning balloons ballot ballot's balloted balloting ballots ballpark ballpark's ballparks ballroom ballroom's ballrooms balls balm balm's balmier balmiest balms balmy baloney baloney's bamboo bamboo's bamboos bamboozle bamboozled bamboozles bamboozling ban banal banaler banalest banalities banality banality's banana banana's bananas band band's bandage bandage's bandaged bandages bandaging bandanna bandanna's bandannas banded bandied bandier bandies bandiest banding bandit bandit's bandits banditti bands bandstand bandstand's bandstands bandwagon bandwagon's bandwagons bandwidth bandwidth's bandy bandying bane bane's baned banes bang bang's banged banging bangle bangle's bangles bangs bani baning banish banished banishes banishing banister banister's banisters banjo banjo's banjoes banjos bank bank's banked banker banker's bankers banking banking's banknote banknotes bankrupt bankrupt's bankruptcies bankruptcy bankruptcy's bankrupted bankrupting bankrupts banks banned banner banner's bannered bannering banners banning banquet banquet's banqueted banqueting banquets bans banter bantered bantering banters baptise baptised baptises baptising baptism baptism's baptismal baptisms bar bar's barb barb's barbarian barbarian's barbarians barbaric barbarism barbarism's barbarisms barbarous barbecue barbecue's barbecued barbecues barbecuing barbed barbell barbell's barbells barber barber's barbered barbering barbers barbing barbiturate barbiturate's barbiturates barbs bard bard's bards bare bareback bared barefoot barely barer bares barest barf barfed barfing barfs bargain bargain's bargained bargainer bargaining bargains barge barge's barged barges barging baring baritone baritone's baritones bark bark's barked barking barks barley barley's barman barman's barn barn's barnacle barnacle's barnacles barns barnyard barnyard's barnyards barometer barometer's barometers barometric baron baron's barons baroque baroque's barrack barracks barrage barrage's barraged barrages barraging barred barrel barrel's barrelled barrelling barrels barren barrener barrenest barrens barrette barrette's barrettes barricade barricade's barricaded barricades barricading barrier barrier's barriers barring barrings barrio barrio's barrios barrister barrister's barristers barroom barroom's barrooms bars bartender bartender's bartenders barter bartered bartering barters base base's baseball baseball's baseballs based baseline baseline's basement basement's basements baser bases basest bash bashed bashes bashful bashing basic basically basics basil basil's basin basin's basing basins basis basis's bask basked basket basket's basketball basketball's basketballs baskets basking basks bass bass's basses bassist bassist's bassists bassoon bassoon's bassoons bastard bastard's bastards baste basted bastes basting bat bat's batch batch's batched batches batching bate bated bates bath bath's bathe bathed bathes bathing bathrobe bathrobe's bathrobes bathroom bathroom's bathrooms baths bathtub bathtub's bathtubs bating baton baton's batons bats batsman batsman's battalion battalion's battalions batted batter battered batteries battering batters battery battery's batting batting's battle battle's battled battlefield battlefield's battlefields battleground battlegrounds battles battleship battleship's battleships battling baud baud's bauds bawdier bawdiest bawdy bawl bawled bawling bawls bay bay's bayed baying bayonet bayonet's bayoneted bayoneting bayonets bayonetted bayonetting bayou bayou's bayous bays bazaar bazaar's bazaars be beach beach's beached beaches beaching beacon beacon's beacons bead bead's beaded beadier beadiest beading beads beady beagle beagle's beagled beagles beagling beak beak's beaked beaker beaker's beakers beaks beam beam's beamed beaming beams bean bean's beaned beaning beans bear bearable beard beard's bearded bearding beards bearer bearer's bearers bearing bearing's bearings bears beast beast's beasts beat beaten beater beater's beaters beating beating's beatings beats beautician beautician's beauticians beauties beautified beautifies beautiful beautifuler beautifulest beautifully beautify beautifying beauty beauty's beaver beaver's beavered beavering beavers bebop bebop's bebops became because beckon beckoned beckoning beckons become becomes becoming becomings bed bed's bedbug bedbug's bedbugs bedclothes bedded bedder bedder's bedding bedding's bedlam bedlam's bedlams bedpan bedpan's bedpans bedraggle bedraggled bedraggles bedraggling bedridden bedrock bedrock's bedrocks bedroom bedroom's bedrooms beds bedside bedside's bedsides bedspread bedspread's bedspreads bedtime bedtime's bedtimes bee bee's beech beech's beeches beef beef's beefed beefier beefiest beefing beefs beefy beehive beehive's beehives beeline beeline's beelined beelines beelining been beep beep's beeped beeper beeper's beepers beeping beeps beer beer's beers bees beeswax beeswax's beet beet's beetle beetle's beetled beetles beetling beets beeves befall befallen befalling befalls befell befit befits befitted befitting before beforehand befriend befriended befriending befriends beg began beggar beggar's beggared beggaring beggars begged begging begin beginner beginner's beginners beginning beginning's beginnings begins begrudge begrudged begrudges begrudging begs beguile beguiled beguiles beguiling begun behalf behalf's behalves behave behaved behaves behaving behaviour behaviour's behavioural behead beheaded beheading beheads beheld behind behinds behold beholder beholder's beholders beholding beholds beige beige's being being's beings belabour belaboured belabouring belabours belated belatedly belch belched belches belching belfries belfry belfry's belie belied belief belief's beliefs belies believable believe believed believer believer's believers believes believing belittle belittled belittles belittling bell bell's bellboy bellboy's bellboys belled bellhop bellhop's bellhops bellied bellies belligerence belligerence's belligerent belligerents belling bellow bellowed bellowing bellows bellows's bells belly belly's bellybutton bellybutton's bellybuttons bellying belong belonged belonging belonging's belongings belongs beloved beloveds below belows belt belt's belted belting belts beltway beltway's beltways belying bemoan bemoaned bemoaning bemoans bemuse bemused bemuses bemusing bench bench's benched benches benching benchmark benchmark's benchmarks bend bender bender's bending bends beneath benediction benediction's benedictions benefactor benefactor's benefactors beneficial beneficiaries beneficiary beneficiary's benefit benefit's benefited benefiting benefits benefitted benefitting benevolence benevolence's benevolences benevolent benighted benign bent bents bequeath bequeathed bequeathing bequeaths bequest bequest's bequests berate berated berates berating bereave bereaved bereavement bereavement's bereavements bereaves bereaving bereft beret beret's berets berried berries berry berry's berrying berserk berth berth's berthed berthing berths beseech beseeched beseeches beseeching beset besets besetting beside besides besiege besieged besieges besieging besought best bested bestial bestiality bestiality's besting bestow bestowed bestowing bestows bests bestseller bestsellers bet bet's beta beta's betcha betray betrayal betrayal's betrayals betrayed betraying betrays betrothal betrothal's betrothals bets betted better bettered bettering betterment betterment's betters betting bettor bettor's bettors between bevel bevelled bevelling bevels beverage beverage's beverages beware bewared bewares bewaring bewilder bewildered bewildering bewilderment bewilderment's bewilders bewitch bewitched bewitches bewitching beyond beyonds bias bias's biased biases biasing biassed biassing bib bib's bible bibles biblical bibliographic bibliographies bibliography bibliography's bibs bicentennial bicentennials bicep biceps biceps's bicepses bicker bickered bickering bickering's bickers bicycle bicycle's bicycled bicycles bicycling bid bidden bidder bidders bidding bidding's bide bided bides biding bids biennial biennials bifocals big bigamist bigamist's bigamists bigamous bigamy bigamy's bigger biggest biggie biggie's biggies bigmouth bigmouth's bigmouths bigot bigot's bigoted bigotries bigotry bigotry's bigots bigwig bigwig's bigwigs bike bike's biked biker bikers bikes biking bikini bikini's bikinis bilateral bilaterally bile bile's bilingual bilinguals bill bill's billboard billboard's billboards billed billfold billfold's billfolds billiards billing billion billion's billionaire billionaire's billionaires billions billionth billionths billow billow's billowed billowing billows bills bimbo bimbo's bimboes bimbos bimonthlies bimonthly bin bin's binaries binary bind binder binder's binders binding binding's bindings binds binge binge's binged bingeing binges binging bingo bingo's binned binning binocular binoculars binomial binomial's bins biochemical biochemistry biochemistry's biodegradable biographer biographer's biographers biographical biographies biography biography's biological biologically biologist biologist's biologists biology biology's biopsied biopsies biopsy biopsy's biopsying bipartisan biped biped's bipeds biplane biplane's biplanes birch birch's birched birches birching bird bird's birdbrained birdcage birdcage's birdcages birded birding birds birdseed birdseed's birth birth's birthday birthday's birthdays birthed birthing birthmark birthmark's birthmarks birthplace birthplace's birthplaces birthrate birthrates births biscuit biscuit's biscuits bisect bisected bisecting bisection bisection's bisections bisects bisexual bisexuals bishop bishop's bishops bison bison's bisons bit bit's bitch bitch's bitched bitches bitchier bitchiest bitching bitchy bite bites biting bitings bitmap bits bitten bitter bitterer bitterest bitterly bitterness bitterness's bittersweet bittersweet's bittersweets biweeklies biweekly bizarre bizarres blab blabbed blabbermouth blabbermouth's blabbermouths blabbing blabs black blackberries blackberry blackberry's blackberrying blackbird blackbird's blackbirds blackboard blackboard's blackboards blacked blacken blackened blackening blackens blacker blackest blackhead blackhead's blackheads blacking blackjack blackjack's blackjacked blackjacking blackjacks blacklist blacklist's blacklisted blacklisting blacklists blackmail blackmail's blackmailed blackmailer blackmailer's blackmailers blackmailing blackmails blackness blackness's blackout blackout's blackouts blacks blacksmith blacksmith's blacksmiths blacktop blacktop's blacktopped blacktopping blacktops bladder bladder's bladders blade blade's bladed blades blading blah blah's blahed blahing blahs blame blame's blamed blameless blamer blames blaming blanch blanched blanches blanching blancmange blancmange's bland blander blandest blandly blank blanked blanker blankest blanket blanket's blanketed blanketing blankets blanking blankly blankness blankness's blanks blare blared blares blaring blaspheme blasphemed blasphemes blasphemies blaspheming blasphemous blasphemy blasphemy's blast blast's blasted blaster blaster's blasting blastoff blastoff's blastoffs blasts blas blatant blatantly blaze blaze's blazed blazer blazer's blazers blazes blazing bleach bleached bleacher bleachers bleaches bleaching bleak bleaker bleakest bleakly bleakness bleakness's blearier bleariest blearily bleary bleat bleated bleating bleats bled bleed bleeding bleeds blemish blemish's blemished blemishes blemishing blend blended blender blender's blenders blending blends blent bless blessed blesseder blessedest blesses blessing blessing's blessings blest blew blight blight's blighted blighting blights blimp blimp's blimps blind blinded blinder blindest blindfold blindfolded blindfolding blindfolds blinding blinding's blindingly blindly blindness blindness's blinds blink blinked blinker blinkered blinkering blinkers blinking blinks blip blip's blips bliss bliss's blissed blisses blissful blissfully blissing blister blister's blistered blistering blisters blithe blithely blither blithest blitz blitz's blitzed blitzes blitzing blizzard blizzard's blizzards bloat bloated bloating bloats blob blob's blobbed blobbing blobs bloc bloc's block block's blockade blockade's blockaded blockades blockading blockage blockage's blockages blockbuster blockbuster's blockbusters blocked blockhead blockhead's blockheads blocking blocks blocs blond blonde blonde's blonder blondes blondest blonds blood blood's bloodbath bloodbaths blooded bloodhound bloodhound's bloodhounds bloodied bloodier bloodies bloodiest blooding bloodless bloods bloodshed bloodshed's bloodshot bloodstain bloodstain's bloodstained bloodstains bloodstream bloodstream's bloodstreams bloodthirstier bloodthirstiest bloodthirsty bloody bloodying bloom bloom's bloomed blooming blooms blooper blooper's bloopers blossom blossom's blossomed blossoming blossoms blot blot's blotch blotch's blotched blotches blotchier blotchiest blotching blotchy blots blotted blotter blotter's blotters blotting blouse blouse's bloused blouses blousing blow blowing blowing's blown blowout blowout's blowouts blows blowtorch blowtorch's blowtorches blowup blowup's blowups blubber blubbered blubbering blubbers bludgeon bludgeon's bludgeoned bludgeoning bludgeons blue blue's bluebell bluebell's bluebells blueberries blueberry blueberry's bluebird bluebird's bluebirds blued bluegrass bluegrass's blueing blueprint blueprint's blueprinted blueprinting blueprints bluer blues bluest bluff bluffed bluffer bluffest bluffing bluffs bluing bluish blunder blunder's blundered blundering blunders blunt blunted blunter bluntest blunting bluntly bluntness bluntness's blunts blur blurb blurb's blurbs blurred blurrier blurriest blurring blurry blurs blurt blurted blurting blurts blush blushed blusher blusher's blushers blushes blushing bluster blustered blustering blusters boa boa's boar boar's board board's boarded boarder boarder's boarders boarding boarding's boardinghouse boardinghouse's boardinghouses boardroom boardroom's boardrooms boards boardwalk boardwalk's boardwalks boars boas boast boasted boastful boastfully boasting boasts boat boat's boated boating boats bob bobbed bobbin bobbin's bobbing bobbins bobcat bobcat's bobcats bobs bobsled bobsled's bobsledded bobsledding bobsleds bode boded bodes bodice bodice's bodices bodies bodily boding body body's bodybuilding bodyguard bodyguard's bodyguards bodywork bodywork's bog bog's bogeyman bogeyman's bogeymen bogged bogging boggle boggled boggles boggling bogs bogus bohemian bohemians boil boiled boiler boiler's boilers boiling boilings boils boisterous bold bolder boldest boldly boldness boldness's bolds bologna bologna's bolster bolstered bolstering bolsters bolt bolt's bolted bolting bolts bomb bombard bombarded bombarding bombardment bombardment's bombardments bombards bombed bomber bomber's bombers bombing bombings bombs bombshell bombshell's bombshells bonanza bonanza's bonanzas bond bond's bondage bondage's bonded bonding bonds bone bone's boned bones boney boneyer boneyest bonfire bonfire's bonfires bongo bongo's bongoes bongos bonier boniest boning bonkers bonnet bonnet's bonnets bonus bonus's bonuses bony boo boob boob's boobed boobing boobs booby booby's booed boogie boogied boogieing boogies booing book book's bookcase bookcase's bookcases booked bookend bookended bookending bookends bookie bookie's bookies booking booking's bookings bookkeeper bookkeeper's bookkeepers bookkeeping bookkeeping's booklet booklet's booklets bookmaker bookmaker's bookmakers bookmark bookmark's bookmarked bookmarking bookmarks books bookshelf bookshelf's bookshop bookshops bookstore bookstore's bookstores bookworm bookworm's bookworms boom boomed boomerang boomerang's boomeranged boomeranging boomerangs booming booms boon boon's boondocks boons boor boor's boorish boors boos boost boost's boosted booster booster's boosters boosting boosts boot boot's booted bootee bootee's bootees booth booth's booths bootie bootie's booties booting bootleg bootlegged bootlegger bootlegger's bootleggers bootlegging bootlegs boots bootstrap bootstrap's bootstraps booty booty's booze booze's boozed boozer boozer's boozers boozes boozing bop bopped bopping bops border border's bordered bordering borderline borderline's borderlines borders bore bored boredom boredom's bores boring boring's boringly born borne borough borough's boroughs borrow borrowed borrower borrower's borrowers borrowing borrowing's borrows bosom bosom's bosoms boss boss's bossed bosser bosses bossier bossiest bossily bossiness bossiness's bossing bossy botanical botanist botanist's botanists botany botany's botch botched botches botching both bother bothered bothering bothers bothersome bottle bottle's bottled bottleneck bottleneck's bottlenecks bottles bottling bottom bottom's bottomed bottoming bottomless bottoms bough bough's boughs bought boulder boulder's bouldered bouldering boulders boulevard boulevard's boulevards bounce bounced bouncer bouncer's bouncers bounces bouncier bounciest bouncing bouncy bound boundaries boundary boundary's bounded bounding boundless bounds bounties bountiful bounty bounty's bouquet bouquet's bouquets bourbon bourbon's bourgeois bourgeois's bourgeoisie bourgeoisie's bout bout's boutique boutique's boutiques bouts bovine bovines bow bowed bowel bowel's bowels bowing bowing's bowl bowl's bowled bowlegged bowler bowler's bowling bowling's bowls bows box box's boxcar boxcar's boxcars boxed boxer boxer's boxers boxes boxing boxing's boy boy's boycott boycotted boycotting boycotts boyfriend boyfriend's boyfriends boyhood boyhood's boyhoods boyish boys bozo bozo's bozos bra bra's brace brace's braced bracelet bracelet's bracelets braces bracing bracket bracket's bracketed bracketing bracketing's brackets brackish brag braggart braggart's braggarts bragged bragging brags braid braided braiding braids brain brain's brainchild brainchild's brainchildren brained brainier brainiest braining brainless brains brainstorm brainstorm's brainstormed brainstorming brainstorms brainwash brainwashed brainwashes brainwashing brainwashing's brainy braise braised braises braising brake brake's braked brakes braking bran bran's branch branch's branched branches branching branching's brand brand's branded brandied brandies branding brandish brandished brandishes brandishing brands brandy brandy's brandying bras brash brasher brashest brass brass's brassed brasses brassier brassiere brassiere's brassieres brassiest brassing brassy brat brat's brats bravado bravado's brave braved bravely braver bravery bravery's braves bravest braving bravo bravos brawl brawl's brawled brawling brawls brawn brawn's brawnier brawniest brawny bray brayed braying brays brazen brazened brazening brazenly brazens brazier brazier's braziers breach breach's breached breaches breaching bread bread's breadbasket breadbasket's breadbaskets breaded breading breads breadth breadth's breadths breadwinner breadwinner's breadwinners break breakable breakables breakdown breakdown's breakdowns breakfast breakfast's breakfasted breakfasting breakfasts breaking breaking's breakneck breakpoints breaks breakthrough breakthrough's breakthroughs breakup breakup's breakups breakwater breakwater's breakwaters breast breast's breasted breasting breasts breaststroke breaststroke's breaststrokes breath breath's breathe breathed breather breather's breathers breathes breathing breathing's breathless breathlessly breaths breathtaking breathtakingly bred breded bredes breding breed breeder breeder's breeders breeding breeding's breeds breeze breeze's breezed breezes breezier breeziest breezing breezy brethren brevity brevity's brew brewed brewer brewer's breweries brewers brewery brewery's brewing brewing's brews bribe bribed bribery bribery's bribes bribing brick brick's bricked bricking bricklayer bricklayer's bricklayers bricklaying bricklaying's bricks bridal bridals bride bride's bridegroom bridegroom's bridegrooms brides bridesmaid bridesmaid's bridesmaids bridge bridge's bridged bridges bridging bridle bridle's bridled bridles bridling brief briefcase briefcase's briefcases briefed briefer briefest briefing briefing's briefings briefly briefs brigade brigade's brigades bright brighten brightened brightening brightens brighter brightest brightly brightness brightness's brights brilliance brilliance's brilliant brilliantly brilliants brim brim's brimmed brimming brims brimstone brimstone's brine brine's bring bringing brings brinier briniest brink brink's brinks briny brisk brisked brisker briskest brisking briskly brisks bristle bristle's bristled bristles bristling britches brittle brittler brittlest broach broached broaches broaching broad broadcast broadcasted broadcaster broadcaster's broadcasters broadcasting broadcasts broaden broadened broadening broadens broader broadest broadly broads broadside broadside's broadsided broadsides broadsiding brocade brocade's brocaded brocades brocading broccoli broccoli's brochure brochure's brochures brogue brogue's brogues broil broiled broiler broiler's broilers broiling broils broke broken brokenhearted broker broker's brokerage brokerage's brokerages brokered brokering brokers bronchitis bronchitis's bronco bronco's broncos bronze bronze's bronzed bronzes bronzing brooch brooch's brooches brood brood's brooded brooding broods brook brook's brooked brooking brooks broom broom's brooms broomstick broomstick's broomsticks broth broth's brothel brothel's brothels brother brother's brothered brotherhood brotherhood's brotherhoods brothering brotherly brothers broths brought brow brow's browbeat browbeaten browbeating browbeats brown brown's browned browner brownest brownie brownie's brownier brownies browniest browning browning's brownish browns brownstone brownstone's brownstones brows browse browsed browser browser's browsers browses browsing bruise bruised bruises bruising brunch brunch's brunched brunches brunching brunette brunette's brunettes brunt brunt's brunted brunting brunts brush brush's brushed brushes brushing brusque brusquer brusquest brutal brutalise brutalised brutalises brutalising brutalities brutality brutality's brutally brute brute's brutes brutish bubble bubble's bubbled bubbles bubblier bubbliest bubbling bubbly buck buck's bucked bucket bucket's bucketed bucketing buckets bucking buckle buckle's buckled buckles buckling bucks bucktoothed bud bud's budded buddies budding buddings buddy buddy's budge budged budges budget budget's budgeted budgeting budgets budging buds buff buff's buffalo buffalo's buffaloed buffaloes buffaloing buffalos buffed buffer buffer's buffered buffering buffers buffet buffet's buffeted buffeting buffets buffing buffoon buffoon's buffoons buffs bug bug's bugged bugger bugger's buggers buggier buggies buggiest bugging buggy buggy's bugle bugle's bugled bugler bugler's buglers bugles bugling bugs build builder builder's builders building building's buildings builds buildup buildups built bulb bulb's bulbed bulbing bulbous bulbs bulge bulge's bulged bulges bulging bulk bulk's bulked bulkier bulkiest bulking bulks bulky bull bull's bulldog bulldog's bulldogged bulldogging bulldogs bulldoze bulldozed bulldozer bulldozer's bulldozers bulldozes bulldozing bulled bullet bullet's bulletin bulletin's bulletined bulletining bulletins bulletproof bulletproofed bulletproofing bulletproofs bullets bullfight bullfight's bullfighter bullfighter's bullfighters bullfighting bullfighting's bullfights bullfrog bullfrog's bullfrogs bullied bullied's bullier bullies bulliest bulling bullion bullion's bullish bulls bullshit bullshit's bullshits bullshitted bullshitting bully bully's bullying bullying's bum bum's bumble bumblebee bumblebee's bumblebees bumbled bumbles bumbling bumblings bummed bummer bummer's bummers bummest bumming bump bumped bumper bumper's bumpers bumpier bumpiest bumping bumps bumpy bums bun bun's bunch bunch's bunched bunches bunching bundle bundle's bundled bundles bundling bung bung's bungalow bungalow's bungalows bungle bungled bungler bungler's bunglers bungles bungling bunion bunion's bunions bunk bunk's bunked bunker bunker's bunkers bunking bunks bunnies bunny bunny's buns buoy buoy's buoyancy buoyancy's buoyant buoyantly buoyed buoying buoys burble burbled burbles burbling burden burden's burdened burdening burdens burdensome bureau bureau's bureaucracies bureaucracy bureaucracy's bureaucrat bureaucrat's bureaucratic bureaucrats bureaus bureaux burger burger's burgers burglar burglar's burglaries burglarise burglarised burglarises burglarising burglars burglary burglary's burgle burial burial's burials buried buries burlap burlap's burlier burliest burly burn burned burner burner's burners burning burnish burnished burnishes burnishing burns burnt burp burp's burped burping burps burr burr's burred burring burro burro's burros burrow burrow's burrowed burrowing burrows burrs bursar bursar's bursars burst bursted bursting bursts bury burying bus bus's busboy busboy's busboys bused buses bush bush's bushed bushel bushel's bushelled bushelling bushellings bushels bushes bushier bushiest bushing bushy busied busier busies busiest busily business business's businesses businesslike businessman businessman's businessmen businesswoman businesswoman's businesswomen busing buss bussed busses bussing bust bust's busted buster buster's busters busting bustle bustled bustles bustling busts busy busybodies busybody busybody's busying busywork busywork's but butcher butcher's butchered butcheries butchering butchers butchery butchery's butler butler's butlered butlering butlers buts butt butt's butte butte's butted butter butter's buttercup buttercup's buttercups buttered butterfingers butterfingers's butterflied butterflies butterfly butterfly's butterflying buttering buttermilk buttermilk's butters butterscotch butterscotch's buttery buttes butting buttock buttock's buttocked buttocking buttocks button button's buttoned buttonhole buttonhole's buttonholed buttonholes buttonholing buttoning buttons buttress buttress's buttressed buttresses buttressing butts buxom buxomer buxomest buy buyer buyer's buyers buying buyout buyouts buys buzz buzz's buzzard buzzard's buzzards buzzed buzzer buzzer's buzzers buzzes buzzing buzzword buzzwords by bye bye's byes bygone bygones bylaw bylaw's bylaws bypass bypass's bypassed bypasses bypassing bypast bystander bystander's bystanders byte byte's bytes byway byway's byways c cab cab's cabaret cabaret's cabarets cabbage cabbage's cabbages cabbed cabbie cabbies cabbing cabby cabby's cabin cabin's cabinet cabinet's cabinets cabins cable cable's cabled cables cabling caboose caboose's cabooses cabs cacao cacao's cacaos cache cache's cached caches cachet cachet's cacheted cacheting cachets caching cackle cackled cackles cackling cacti cactus cactus's cactuses cad cad's cadaver cadaver's cadavers caddie caddie's caddied caddieing caddies caddy cadence cadence's cadences cadet cadet's cadets cadre cadre's cadres cafeteria cafeteria's cafeterias caffeine caffeine's caf cafs cage cage's caged cages cagey cagier cagiest caging cagy cahoot cahoots cajole cajoled cajoles cajoling cake cake's caked cakes caking calamities calamity calamity's calcium calcium's calculate calculated calculates calculating calculation calculation's calculations calculator calculator's calculators calculi calculus calculus's calculuses calendar calendar's calendared calendaring calendars calf calf's calfs calibrate calibrated calibrates calibrating calibration calibration's calibrations calibre calibre's calibres calico calico's calicoes calicos call callable called caller caller's callers calligraphy calligraphy's calling calling's callings callous calloused callouses callousing callously callousness callousness's callow calls callus callus's callused calluses callusing calm calmed calmer calmest calming calmly calmness calmness's calms calorie calorie's calories calve calves calves's cam cam's camaraderie camaraderie's camcorder camcorders came camel camel's camellia camellia's camellias camels cameo cameo's cameoed cameoing cameos camera camera's camerae cameraman cameraman's cameramen cameras camerawoman camerawomen camouflage camouflage's camouflaged camouflages camouflaging camp camp's campaign campaign's campaigned campaigner campaigner's campaigners campaigning campaigns camped camper camper's campers campest campground campground's campgrounds camping camps campsite campsite's campsites campus campus's campused campuses campusing can can's can't canal canal's canals canaries canary canary's cancel cancellation cancellation's cancellations cancelled cancelling cancels cancer cancer's cancers candid candidacies candidacy candidacy's candidate candidate's candidates candider candidest candidly candied candies candle candle's candled candlelight candlelight's candles candlestick candlestick's candlesticks candling candour candour's candy candy's candying cane cane's caned canes canine canines caning canister canister's canistered canistering canisters canker canker's cankered cankering cankers cannabis cannabis's cannabises canned canneries cannery cannery's cannibal cannibal's cannibalism cannibalism's cannibals cannier canniest canning cannon cannon's cannonball cannonball's cannonballed cannonballing cannonballs cannoned cannoning cannons cannot canny canoe canoe's canoed canoes canon canon's canonical canons canopied canopies canopy canopy's canopying cans cant cant's cantaloupe cantaloupe's cantaloupes cantankerous canteen canteen's canteens canter canter's cantered cantering canters canvas canvas's canvased canvases canvasing canvass canvassed canvasser canvassers canvasses canvassing canyon canyon's canyons cap cap's capabilities capability capability's capable capabler capablest capably capacitance capacitance's capacities capacitor capacitor's capacitors capacity capacity's cape cape's caped caper caper's capered capering capers capes capillaries capillary capital capital's capitalisation capitalisation's capitalise capitalised capitalises capitalising capitalism capitalism's capitalist capitalist's capitalists capitals capitol capitols capitulate capitulated capitulates capitulating capitulation capitulation's capitulations capped capping cappuccino cappuccino's cappuccinos caprice caprice's caprices capricious capriciously caps capsize capsized capsizes capsizing capsule capsule's capsuled capsules capsuling captain captain's captained captaining captains caption caption's captioned captioning captions captivate captivated captivates captivating captive captive's captives captivities captivity captivity's captor captor's captors capture captured captures capturing car car's caramel caramel's caramels carat carat's carats caravan caravan's caravans carbohydrate carbohydrate's carbohydrates carbon carbon's carbonate carbonated carbonates carbonating carbons carburetor carburetor's carburetors carcass carcass's carcasses carcinogenic card card's cardboard cardboard's carded cardiac cardigan cardigan's cardigans cardinal cardinal's cardinals carding cardiology cardiology's cards care cared careen careened careening careens career career's careered careering careers carefree careful carefuller carefullest carefully carefulness carefulness's careless carelessly carelessness carelessness's cares caress caress's caressed caresses caressing caretaker caretaker's caretakers cargo cargo's cargoes cargos caribou caribou's caribous caricature caricature's caricatured caricatures caricaturing caring carjack carjacked carjacker carjackers carjacking carjackings carjacks carnage carnage's carnal carnation carnation's carnations carnival carnival's carnivals carnivore carnivore's carnivores carnivorous carol carol's carolled carolling carols carouse caroused carousel carousel's carousels carouses carousing carp carp's carped carpenter carpenter's carpentered carpentering carpenters carpentry carpentry's carpet carpet's carpeted carpeting carpeting's carpets carping carps carriage carriage's carriages carriageway carriageway's carried carrier carrier's carriers carries carrion carrion's carrot carrot's carrots carry carrying carryout carryouts cars cart cart's carted cartel cartel's cartels cartilage cartilage's cartilages carting cartographer cartographer's cartographers cartography cartography's carton carton's cartons cartoon cartoon's cartooned cartooning cartoonist cartoonist's cartoonists cartoons cartridge cartridge's cartridges carts cartwheel cartwheel's cartwheeled cartwheeling cartwheels carve carved carves carving carving's carvings cascade cascade's cascaded cascades cascading case case's cased cases casework casework's caseworker caseworker's caseworkers cash cash's cashed cashes cashew cashew's cashews cashier cashier's cashiered cashiering cashiers cashing cashmere cashmere's casing casing's casings casino casino's casinos cask cask's casket casket's caskets casks casserole casserole's casseroled casseroles casseroling cassette cassette's cassettes cast castaway castaway's castaways caste caste's casted caster caster's casters castes castigate castigated castigates castigating castigation castigation's casting casting's castings castle castle's castled castles castling castoff castoffs castrate castrated castrates castrating castration castration's castrations casts casual casually casualness casualness's casuals casualties casualty casualty's cat cat's cataclysm cataclysm's cataclysmic cataclysms catalogue catalogue's catalogued catalogues cataloguing catalyst catalyst's catalysts catamaran catamaran's catamarans catapult catapult's catapulted catapulting catapults cataract cataract's cataracts catastrophe catastrophe's catastrophes catastrophic catcall catcall's catcalled catcalling catcalls catch catches catchier catchiest catching catchings catchment catchment's catchy catechism catechism's catechisms categorical categorically categories categorise categorised categorises categorising category category's cater catered caterer caterer's caterers catering catering's caterings caterpillar caterpillar's caterpillars caters catfish catfish's catfishes cathedral cathedral's cathedrals catholic catholics catnap catnap's catnapped catnapping catnaps catnip catnip's cats catsup catsup's cattier cattiest cattle cattle's catty catwalk catwalk's catwalks caucus caucus's caucused caucuses caucusing caucussed caucusses caucussing caught cauliflower cauliflower's cauliflowers caulk caulked caulking caulks causal causality causality's cause cause's caused causes causeway causeway's causeways causing caustic caustics caution caution's cautionary cautioned cautioning cautions cautious cautiously cavalier cavaliers cavalries cavalry cavalry's cave cave's caveat caveat's caveats caved caveman caveman's cavemen cavern cavern's caverns caves caviar caviar's caving caving's cavities cavity cavity's cavort cavorted cavorting cavorts caw caw's cawed cawing caws cease ceased ceasefire ceaseless ceaselessly ceases ceasing cedar cedar's cedars cede ceded cedes ceding ceiling ceiling's ceilings celebrate celebrated celebrates celebrating celebration celebration's celebrations celebrities celebrity celebrity's celery celery's celestial celibacy celibacy's celibate celibate's celibates cell cell's cellar cellar's cellars celled celli celling cellist cellist's cellists cello cello's cellophane cellophane's cellos cells cellular cellulars celluloid celluloid's cellulose cellulose's cement cement's cemented cementing cements cemeteries cemetery cemetery's censor censor's censored censoring censors censorship censorship's censure censure's censured censures censuring census census's censused censuses censusing cent cent's centenaries centenary centennial centennials centigrade centimetre centimetre's centimetres centipede centipede's centipedes central centraler centralest centralise centralised centralises centralising centrally centrals centre centre's centred centrepiece centrepiece's centrepieces centres centrifuge centrifuge's centring cents centuries century century's ceramic ceramic's ceramics cereal cereal's cereals cerebral ceremonial ceremonials ceremonies ceremonious ceremony ceremony's certain certainer certainest certainly certainties certainty certainty's certifiable certificate certificate's certificated certificates certificating certification certification's certifications certified certifies certify certifying cervical cervices cervix cervix's cervixes cesarean cesareans cessation cessation's cessations cesspool cesspool's cesspools chafe chafed chafes chaff chaff's chaffed chaffing chaffs chafing chagrin chagrin's chagrined chagrining chagrinned chagrinning chagrins chain chain's chained chaining chains chainsaw chainsawed chainsawing chainsaws chair chair's chaired chairing chairman chairman's chairmanship chairmanship's chairmen chairperson chairpersons chairs chairwoman chairwoman's chairwomen chalet chalet's chalets chalice chalice's chalices chalk chalk's chalkboard chalkboard's chalkboards chalked chalkier chalkiest chalking chalks chalky challenge challenged challenger challenger's challengers challenges challenging chamber chamber's chambers chameleon chameleon's chameleons champ champagne champagne's champagnes champed champing champion champion's championed championing champions championship championship's championships champs chance chance's chanced chancellor chancellor's chancellors chances chancing chandelier chandelier's chandeliers change changeable changed changeover changeover's changeovers changes changing channel channel's channelled channelling channels chant chant's chanted chanting chants chaos chaos's chaotic chap chapel chapel's chapels chaperon chaperon's chaperone chaperone's chaperoned chaperones chaperoning chaperons chaplain chaplain's chaplains chapped chapping chaps chapt chapter chapter's chapters char character character's characterisation characterisation's characterisations characterise characterised characterises characterising characteristic characteristic's characteristically characteristics characters charade charade's charades charcoal charcoal's charcoals charge chargeable charged charger charger's charges charging chariot chariot's chariots charisma charisma's charismatic charismatics charitable charitably charities charity charity's charlatan charlatan's charlatans charm charm's charmed charmer charmer's charmers charming charminger charmingest charms charred charring chars chart chart's charted charter charter's chartered chartering charters charting charts chase chased chases chasing chasing's chasm chasm's chasms chassis chassis's chaste chasten chastened chastening chastens chaster chastest chastise chastised chastisement chastisement's chastisements chastises chastising chastity chastity's chat chat's chateaus chats chatted chatter chatterbox chatterbox's chatterboxes chattered chattering chatters chattier chattiest chatting chatty chauffeur chauffeur's chauffeured chauffeuring chauffeurs chauvinism chauvinism's chauvinist chauvinist's chauvinistic chauvinists cheap cheapen cheapened cheapening cheapens cheaper cheapest cheaply cheapness cheapness's cheapskate cheapskate's cheapskates cheat cheated cheater cheater's cheaters cheating cheats check check's checked checker checker's checkered checkering checkers checking checklist checklists checkmate checkmate's checkmated checkmates checkmating checkout checkouts checkpoint checkpoint's checkpoints checks checkup checkup's checkups cheddar cheek cheek's cheekbone cheekbone's cheekbones cheeked cheeking cheeks cheep cheep's cheeped cheeping cheeps cheer cheered cheerful cheerfuller cheerfullest cheerfully cheerfulness cheerfulness's cheerier cheeriest cheering cheerleader cheerleader's cheerleaders cheers cheerses cheery cheese cheese's cheeseburger cheeseburger's cheeseburgers cheesecake cheesecake's cheesecakes cheesecloth cheesecloth's cheesed cheeses cheesing cheetah cheetah's cheetahs chef chef's cheffed cheffing chefs chemical chemical's chemically chemicals chemist chemist's chemistry chemistry's chemists chemotherapy chemotherapy's cheque cheque's chequebook chequebook's chequebooks chequer chequer's chequerboard chequerboard's chequerboards chequered chequering chequers cheques cherish cherished cherishes cherishing cherries cherry cherry's cherub cherub's cherubim cherubs chess chess's chessboard chessboard's chessboards chest chest's chestnut chestnut's chestnuts chests chew chewed chewier chewiest chewing chews chewy chi chi's chic chicer chicest chick chick's chickadee chickadee's chickadees chicken chicken's chickened chickening chickens chicks chid chidden chide chided chides chiding chief chief's chiefer chiefest chiefly chiefs chieftain chieftain's chieftains chiffon chiffon's child child's childbearing childbearing's childbirth childbirth's childbirths childcare childed childes childhood childhood's childhoods childing childish childishly childless childlike childproof childproofed childproofing childproofs children children's chili chili's chilies chill chill's chilled chiller chiller's chillest chilli chillier chillies chilliest chilling chillings chills chilly chime chime's chimed chimes chiming chimney chimney's chimneys chimp chimp's chimpanzee chimpanzee's chimpanzees chimps chin china china's chink chink's chinked chinking chinks chinned chinning chino chinos chins chintz chintz's chip chip's chipmunk chipmunk's chipmunks chipped chipper chippers chipping chips chiropractor chiropractor's chiropractors chirp chirped chirping chirps chisel chisel's chiseled chiseling chiselled chiselling chisels chit chit's chitchat chitchat's chitchats chitchatted chitchatting chits chivalrous chivalry chivalry's chive chives chlorinate chlorinated chlorinates chlorinating chlorine chlorine's chloroform chloroform's chloroformed chloroforming chloroforms chlorophyll chlorophyll's chocolate chocolate's chocolates choice choice's choicer choices choicest choir choir's choirs choke choked chokes choking cholera cholera's cholesterol cholesterol's choose chooses choosey choosier choosiest choosing choosy chop chopped chopper chopper's choppered choppering choppers choppier choppiest choppiness choppiness's chopping choppy chops chopstick chopsticks choral chorals chord chord's chords chore chore's chored choreograph choreographed choreographer choreographer's choreographers choreographing choreographs choreography choreography's chores choring chortle chortled chortles chortling chorus chorus's chorused choruses chorusing chorussed chorusses chorussing chose chosen chow chow's chowder chowder's chowdered chowdering chowders chowed chowing chows christen christened christening christening's christenings christens chrome chrome's chromed chromes chroming chromium chromium's chromosome chromosome's chromosomes chronic chronically chronicle chronicle's chronicled chronicles chronicling chronics chronological chronologically chronologies chronology chronology's chrysanthemum chrysanthemum's chrysanthemums chubbier chubbiest chubby chuck chucked chucking chuckle chuckled chuckles chuckling chucks chug chug's chugged chugging chugs chum chum's chummed chummier chummies chummiest chumming chummy chump chump's chumps chums chunk chunk's chunkier chunkiest chunks chunky church church's churches churchgoer churchgoer's churchgoers churlish churn churn's churned churning churning's churns chute chute's chutes chutzpah chutzpah's chteau chteau's chteaux cider cider's ciders cigar cigar's cigarette cigarette's cigarettes cigars cinch cinch's cinched cinches cinching cinder cinder's cindered cindering cinders cinema cinema's cinemas cinematographer cinematographer's cinematographers cinnamon cinnamon's cipher cipher's ciphered ciphering ciphers circa circle circle's circled circles circling circuit circuit's circuited circuiting circuitous circuitry circuitry's circuits circular circulars circulate circulated circulates circulating circulation circulation's circulations circulatory circumcise circumcised circumcises circumcising circumcision circumcision's circumcisions circumference circumference's circumferences circumflex circumflex's circumstance circumstance's circumstanced circumstances circumstancing circumstantial circumstantials circumvent circumvented circumventing circumvention circumvention's circumvents circus circus's circuses cirrhosis cirrhosis's cistern cistern's cisterns citation citation's citations cite cited cites cities citing citizen citizen's citizens citizenship citizenship's citric citrus citrus's citruses city city's civic civics civics's civil civilian civilian's civilians civilisation civilisation's civilisations civilise civilised civilises civilising civilities civility civility's civilly clack clacked clacking clacks clad claim claimed claiming claims clairvoyance clairvoyance's clairvoyant clairvoyants clam clam's clamber clambered clambering clambers clammed clammier clammiest clamming clammy clamour clamour's clamoured clamouring clamours clamp clamp's clampdown clampdown's clampdowns clamped clamping clamps clams clan clan's clandestine clang clanged clanging clangs clank clank's clanked clanking clanks clans clap clapboard clapboard's clapboarded clapboarding clapboards clapped clapper clapper's clappered clappering clappers clapping claps claptrap claptrap's claret claret's clarification clarification's clarifications clarified clarifies clarify clarifying clarinet clarinet's clarinets clarity clarity's clash clashed clashes clashing clasp clasp's clasped clasping clasps class class's classed classes classic classical classically classics classics's classier classiest classification classification's classifications classified classifieds classifies classify classifying classing classmate classmate's classmates classroom classroom's classrooms classy clatter clattered clattering clatters clause clause's clauses claustrophobia claustrophobia's claustrophobic claw claw's clawed clawing claws clay clay's clean cleaned cleaner cleaner's cleaners cleanest cleaning cleaning's cleanings cleanlier cleanliest cleanliness cleanliness's cleanly cleans cleanse cleansed cleanser cleanser's cleansers cleanses cleansing cleanup cleanup's cleanups clear clearance clearance's clearances cleared clearer clearer's clearest clearing clearing's clearings clearly clearness clearness's clears cleat cleat's cleats cleavage cleavage's cleavages cleave cleaved cleaver cleaver's cleavers cleaves cleaving clef clef's clefs cleft clefted clefting clefts clemency clemency's clench clenched clenches clenching clergies clergy clergy's clergyman clergyman's clergymen clergywoman clergywomen cleric cleric's clerical clerics clerk clerk's clerked clerking clerks clever cleverer cleverest cleverly cleverness cleverness's cleves clich clich's clichs click click's clicked clicking clicks client client's clients clientle clientle's clientles cliff cliff's cliffhanger cliffhanger's cliffhangers cliffs climactic climate climate's climates climatic climax climax's climaxed climaxes climaxing climb climbed climber climber's climbers climbing climbs clime climes clinch clinched clinches clinching cling clinging clings clinic clinic's clinical clinically clinician clinician's clinicians clinics clink clinked clinking clinks clip clipboard clipboard's clipboards clipped clipper clippers clipping clipping's clippings clips clipt clique clique's cliques clitoris clitoris's clitorises cloak cloak's cloaked cloaking cloakroom cloakroom's cloakrooms cloaks clobber clobbered clobbering clobbers clock clock's clocked clocking clocks clockwise clockwork clockwork's clockworks clod clod's clodded clodding clods clog clogged clogging clogs cloister cloister's cloistered cloistering cloisters clone clone's cloned clones cloning close closed closely closeness closeness's closeout closeout's closeouts closer closer's closes closest closet closet's closeted closeting closets closing closure closure's closures clot clot's cloth cloth's clothe clothed clothes clothesline clothesline's clotheslined clotheslines clotheslining clothespin clothespin's clothespins clothing clothing's cloths clots clotted clotting cloud cloud's cloudburst cloudburst's cloudbursts clouded cloudier cloudiest clouding cloudless clouds cloudy clout clout's clouted clouting clouts clove clove's cloven clover clover's clovers cloves clown clown's clowned clowning clowns club club's clubbed clubbing clubhouse clubhouse's clubhouses clubs cluck cluck's clucked clucking clucks clue clue's clued clueing clueless clues cluing clump clump's clumped clumping clumps clumsier clumsiest clumsily clumsiness clumsiness's clumsy clung clunk clunk's clunked clunking clunks cluster cluster's clustered clustering clusters clutch clutched clutches clutching clutter cluttered cluttering clutters coach coach's coached coaches coaching coagulate coagulated coagulates coagulating coagulation coagulation's coal coal's coaled coalesce coalesced coalesces coalescing coaling coalition coalition's coalitions coals coarse coarsely coarsen coarsened coarseness coarseness's coarsening coarsens coarser coarsest coast coast's coastal coasted coaster coaster's coasters coasting coastline coastline's coastlines coasts coat coat's coated coater coating coating's coatings coats coattest coax coaxed coaxes coaxing cob cob's cobalt cobalt's cobbed cobbing cobble cobble's cobbler cobbler's cobblers cobblestone cobblestone's cobblestones cobra cobra's cobras cobs cobweb cobweb's cobwebs cocaine cocaine's cock cock's cocked cockeyed cockier cockiest cockiness cockiness's cocking cockpit cockpit's cockpits cockroach cockroach's cockroaches cocks cocktail cocktail's cocktails cocky cocoa cocoa's cocoas coconut coconut's coconuts cocoon cocoon's cocooned cocooning cocoons cod cod's codded codding code code's coded codes coding coding's cods coed coed's coeds coeducational coefficient coefficient's coefficients coerce coerced coerces coercing coercion coercion's coercive coexist coexisted coexistence coexistence's coexisting coexists coffee coffee's coffeehouse coffeehouse's coffeehouses coffees coffer coffer's coffers coffin coffin's coffined coffining coffins cog cog's cogency cogency's cogent cogently cognac cognac's cognacs cognitive cogs cohabit cohabitation cohabitation's cohabited cohabiting cohabits coherence coherence's coherent coherently cohesion cohesion's coil coiled coiling coils coin coin's coinage coinage's coinages coincide coincided coincidence coincidence's coincidences coincidental coincidentally coincides coinciding coined coining coins coke coke's coked cokes coking cola cola's colander colander's colanders colas cold colder coldest coldly coldness coldness's colds coleslaw coleslaw's colic colic's collaborate collaborated collaborates collaborating collaboration collaboration's collaborations collaborative collaborator collaborator's collaborators collage collage's collages collapse collapsed collapses collapsible collapsing collar collar's collarbone collarbone's collarbones collared collaring collars collate collated collateral collateral's collates collating collation collation's colleague colleague's colleagued colleagues colleaguing collect collected collectible collectibles collecting collection collection's collections collective collectively collectives collector collector's collectors collects college college's colleges collegiate collide collided collides colliding collie collie's collied collies collision collision's collisions colloquial colloquialism colloquialism's colloquialisms colloquially colloquials collusion collusion's collying cologne cologne's colognes colon colon's colonel colonel's colonels colonial colonialism colonialism's colonials colonies colonisation colonisation's colonise colonised colonises colonising colonist colonist's colonists colons colony colony's colossal colour colour's colourblind coloured coloureds colourful colouring colouring's colourless colours colt colt's colts column column's columnist columnist's columnists columns coma coma's comae comas comatose comb comb's combat combat's combatant combatant's combatants combated combating combative combats combatted combatting combed combination combination's combinations combine combined combines combing combining combs combustible combustibles combustion combustion's come comeback comeback's comebacks comedian comedian's comedians comedies comedown comedown's comedowns comedy comedy's comelier comeliest comely comes comes's comestible comestibles comet comet's comets comeuppance comeuppance's comeuppances comfier comfiest comfort comfort's comfortable comfortably comforted comforter comforter's comforters comforting comforts comfy comic comical comics coming comings comma comma's command commandant commandant's commandants commanded commandeer commandeered commandeering commandeers commander commander's commanders commanding commandment commandment's commandments commando commando's commandoes commandos commands commas commemorate commemorated commemorates commemorating commemoration commemoration's commemorations commemorative commence commenced commencement commencement's commencements commences commencing commend commendable commendation commendation's commendations commended commending commends comment comment's commentaries commentary commentary's commentate commentated commentates commentating commentator commentator's commentators commented commenting comments commerce commerce's commerced commerces commercial commercialise commercialised commercialises commercialising commercialism commercialism's commercially commercials commercing commiserate commiserated commiserates commiserating commiseration commiseration's commiserations commission commission's commissioned commissioner commissioner's commissioners commissioning commissions commit commitment commitment's commitments commits committed committee committee's committees committing commodities commodity commodity's commodore commodore's commodores common commoner commoner's commonest commonly commonplace commonplaces commons commons's commonwealth commonwealth's commonwealths commotion commotion's commotions communal commune communed communes communicable communicate communicated communicates communicating communication communication's communications communicative communicator communicator's communing communion communion's communions communique communiques communism communism's communist communist's communists communities community community's commutative commute commuted commuter commuter's commuters commutes commuting compact compacted compacter compactest compacting compaction compaction's compacts companies companion companion's companionable companions companionship companionship's company company's comparable comparative comparatively comparatives compare compared compares comparing comparison comparison's comparisons compartment compartment's compartmentalise compartmentalised compartmentalises compartmentalising compartments compass compass's compassed compasses compassing compassion compassion's compassionate compatibility compatibility's compatible compatibles compatriot compatriot's compatriots compel compelled compelling compelling's compels compensate compensated compensates compensating compensation compensation's compensations compensatory compete competed competence competence's competences competent competently competes competing competition competition's competitions competitive competitively competitiveness competitiveness's competitor competitor's competitors compilation compilation's compilations compile compiled compiler compiler's compilers compiles compiling complacency complacency's complacent complain complained complaining complains complaint complaint's complaints complement complement's complementary complemented complementing complements complete completed completely completeness completeness's completer completes completest completing completion completion's complex complexer complexes complexest complexion complexion's complexioned complexions complexities complexity complexity's compliance compliance's compliant complicate complicated complicates complicating complication complication's complications complices complicity complicity's complied complies compliment compliment's complimentary complimented complimenting compliments comply complying component component's components compose composed composer composer's composers composes composing composite composites composition composition's compositions compost compost's composted composting composts composure composure's compound compound's compounded compounding compounds comprehend comprehended comprehending comprehends comprehensible comprehension comprehension's comprehensions comprehensive comprehensively comprehensives compress compressed compresses compressing compression compression's comprise comprised comprises comprising compromise compromise's compromised compromises compromising compulsion compulsion's compulsions compulsive compulsories compulsory compunction compunction's compunctions computation computation's computational computations compute computed computer computer's computerise computerised computerises computerising computers computes computing comrade comrade's comrades comradeship comradeship's con con's concatenate concatenated concatenates concatenating concatenation concatenation's concatenations concave conceal concealed concealing concealment concealment's conceals concede conceded concedes conceding conceit conceit's conceited conceits conceivable conceivably conceive conceived conceives conceiving concentrate concentrated concentrates concentrating concentration concentration's concentrations concentric concept concept's conception conception's conceptions concepts conceptual conceptually concern concerned concerning concerns concert concert's concerted concerti concerting concerto concerto's concertos concerts concession concession's concessions concierge concierge's concierges conciliate conciliated conciliates conciliating conciliation conciliation's conciliatory concise concisely conciseness conciseness's conciser concisest conclude concluded concludes concluding conclusion conclusion's conclusions conclusive conclusively concoct concocted concocting concoction concoction's concoctions concocts concord concord's concordance concordance's concourse concourse's concourses concrete concrete's concreted concretely concretes concreting concur concurred concurrence concurrence's concurrences concurrency concurrent concurrently concurring concurs concussion concussion's concussions condemn condemnation condemnation's condemnations condemned condemning condemns condensation condensation's condensations condense condensed condenses condensing condescend condescended condescending condescends condescension condescension's condiment condiment's condiments condition condition's conditional conditionally conditionals conditioned conditioner conditioner's conditioners conditioning conditioning's conditions condo condoes condolence condolence's condolences condom condom's condominium condominium's condominiums condoms condone condoned condones condoning condor condor's condores condors condos conducive conduct conduct's conducted conducting conductor conductor's conductors conducts cone cone's cones confection confection's confections confederacies confederacy confederacy's confederate confederate's confederated confederates confederating confederation confederation's confederations confer conference conference's conferences conferred conferrer conferring confers confess confessed confesses confessing confession confession's confessions confetti confetti's confidant confidant's confidants confide confided confidence confidence's confidences confident confidential confidentiality confidentiality's confidentially confidently confides confiding configurable configuration configuration's configurations configure configured configures configuring confine confined confinement confinement's confinements confines confining confirm confirmation confirmation's confirmations confirmed confirming confirms confiscate confiscated confiscates confiscating confiscation confiscation's confiscations conflict conflict's conflicted conflicting conflicts conform conformed conforming conformist conformist's conformists conformity conformity's conforms confound confounded confounding confounds confront confrontation confrontation's confrontations confronted confronting confronts confuse confused confuses confusing confusion confusion's congeal congealed congealing congeals congenial congenital congest congested congesting congestion congestion's congests conglomerate conglomerate's conglomerated conglomerates conglomerating congratulate congratulated congratulates congratulating congratulations congratulatory congregate congregated congregates congregating congregation congregation's congregations congress congress's congresses congressional congressman congressman's congressmen congresswoman congresswoman's congresswomen congruent conical conicals conifer conifer's coniferous conifers conjecture conjecture's conjectured conjectures conjecturing conjugal conjugate conjugated conjugates conjugating conjugation conjugation's conjugations conjunction conjunction's conjunctions conjure conjured conjures conjuring connect connected connecting connection connection's connections connective connectivity connectivity's connector connector's connectors connects conned connexion connexion's conning connivance connivance's connive connived connives conniving connoisseur connoisseur's connoisseurs connotation connotation's connotations connote connoted connotes connoting conquer conquered conquering conqueror conqueror's conquerors conquers conquest conquest's conquests cons conscience conscience's consciences conscientious conscientiously conscious consciouses consciously consciousness consciousness's consciousnesses consecrate consecrated consecrates consecrating consecration consecration's consecrations consecutive consecutively consensus consensus's consensuses consent consented consenting consents consequence consequence's consequences consequent consequential consequently conservation conservation's conservationist conservationist's conservationists conservatism conservatism's conservative conservatively conservatives conservator conservator's conservatories conservators conservatory conservatory's conserve conserved conserves conserving consider considerable considerably considerate considerately consideration consideration's considerations considered considering considerings considers consign consigned consigning consignment consignment's consignments consigns consist consisted consistencies consistency consistency's consistent consistently consisting consists consolation consolation's consolations console consoled consoles consolidate consolidated consolidates consolidating consolidation consolidation's consolidations consoling consomm consonant consonant's consonants consort consorted consortia consorting consortium consortium's consortiums consorts conspicuous conspicuously conspiracies conspiracy conspiracy's conspirator conspirator's conspiratorial conspirators conspire conspired conspires conspiring constancy constancy's constant constantly constants constellation constellation's constellations consternation consternation's constipate constipated constipates constipating constipation constipation's constituencies constituency constituency's constituent constituents constitute constituted constitutes constituting constitution constitution's constitutional constitutionally constitutionals constitutions constrain constrained constraining constrains constraint constraint's constraints constrict constricted constricting constriction constriction's constrictions constricts construct constructed constructing construction construction's constructions constructive constructively constructs construe construed construes construing consul consul's consular consulars consulate consulate's consulates consuls consult consultancy consultant consultant's consultants consultation consultation's consultations consulted consulting consults consumable consumables consume consumed consumer consumer's consumerism consumerism's consumers consumes consuming consumings consummate consummated consummates consummating consummation consummation's consummations consumption consumption's contact contact's contacted contacting contacts contagion contagion's contagions contagious contain contained container container's containers containing contains contaminate contaminated contaminates contaminating contamination contamination's contemplate contemplated contemplates contemplating contemplation contemplation's contemplative contemplatives contemporaries contemporary contempt contempt's contemptible contemptuous contend contended contender contenders contending contends content content's contented contentedly contenting contention contention's contentions contentious contentment contentment's contents contest contest's contestant contestant's contestants contested contesting contests context context's contexts contextual contiguous continent continent's continental continentals continents contingencies contingency contingency's contingent contingents continual continually continuation continuation's continuations continue continued continues continuing continuity continuity's continuous continuously continuum continuum's contort contorted contorting contortion contortion's contortions contorts contour contour's contoured contouring contours contraband contraband's contraception contraception's contraceptive contraceptives contract contracted contracting contraction contraction's contractions contractor contractor's contractors contracts contractual contradict contradicted contradicting contradiction contradiction's contradictions contradictory contradicts contraption contraption's contraptions contraries contrary contrast contrasted contrasting contrasts contravene contravened contravenes contravening contravention contravention's contraventions contribute contributed contributes contributing contribution contribution's contributions contributor contributor's contributors contributory contrite contrition contrition's contrive contrived contrives contriving control controllable controlled controller controller's controllers controlling controls controversial controversies controversy controversy's convalesce convalesced convalescence convalescence's convalescences convalescent convalescents convalesces convalescing convection convection's convene convened convenes convenience convenience's conveniences convenient conveniently convening convent convent's convented conventing convention convention's conventional conventionally conventions convents converge converged convergence convergence's converges converging conversant conversation conversation's conversational conversations converse conversed conversely converses conversing conversion conversion's conversions convert converted converter converter's converters convertible convertibles converting converts convex convexed convexes convexing convey conveyance conveyance's conveyances conveyed conveying conveys convict convicted convicting conviction conviction's convictions convicts convince convinced convinces convincing convincingly convivial convoluted convoy convoy's convoyed convoying convoys convulse convulsed convulses convulsing convulsion convulsion's convulsions convulsive coo cooed cooing cook cook's cookbook cookbook's cookbooks cooked cooker cooker's cookie cookie's cookies cooking cooking's cookout cookout's cookouts cooks cooky cool cooled cooler cooler's coolers coolest cooling coolly coolness coolness's cools coop coop's cooped cooper cooper's cooperate cooperated cooperates cooperating cooperation cooperation's cooperative cooperatives cooping coops coordinate coordinated coordinates coordinating coordination coordination's coordinator coordinator's coordinators coos cop cop's cope coped copes copied copier copier's copiers copies copilot copilot's copilots coping coping's copious copiously copped copper copper's copperhead copperhead's copperheads coppers copping cops copter copter's copters copulate copulated copulates copulating copulation copulation's copy copy's copying copyright copyright's copyrighted copyrighting copyrights coral coral's corals cord cord's corded cordial cordiality cordiality's cordially cordials cording cordless cordon cordon's cordoned cordoning cordons cords corduroy corduroy's core core's cored cores coring cork cork's corked corking corks corkscrew corkscrew's corkscrewed corkscrewing corkscrews corn corn's cornbread cornea cornea's corneas corned corner corner's cornered cornering corners cornerstone cornerstone's cornerstones cornet cornet's cornets cornflakes cornier corniest corning cornmeal corns cornstarch cornstarch's corny corollary corollary's coronaries coronary coronation coronation's coronations coroner coroner's coroners corporal corporals corporate corporation corporation's corporations corps corps's corpse corpse's corpses corpulent corpus corpus's corpuscle corpuscle's corpuscles corral corral's corralled corralling corrals correct corrected correcter correctest correcting correction correction's corrections corrective correctives correctly correctness correctness's corrector corrector's corrects correlate correlated correlates correlating correlation correlation's correlations correspond corresponded correspondence correspondence's correspondences correspondent correspondent's correspondents corresponding correspondingly corresponds corridor corridor's corridors corroborate corroborated corroborates corroborating corroboration corroboration's corroborations corrode corroded corrodes corroding corrosion corrosion's corrosive corrosives corrugate corrugated corrugates corrugating corrupt corrupted corrupter corruptest corruptible corrupting corruption corruption's corruptions corrupts corsage corsage's corsages corset corset's corseted corseting corsets cortex cortex's cosier cosies cosiest cosmetic cosmetic's cosmetics cosmic cosmology cosmology's cosmonaut cosmonaut's cosmonauts cosmopolitan cosmopolitan's cosmopolitans cosmos cosmos's cosmoses cost cost's costar costarred costarring costars costing costings costlier costliest costly costs costume costume's costumed costumes costuming cosy cot cot's coting cots cottage cottage's cottaged cottages cottaging cotted cotton cotton's cottoned cottoning cottons cottontail cottontail's cottontails cottonwood cottonwood's cottonwoods couch couch's couched couches couching cougar cougar's cougars cough coughed coughing coughs could couldn't council council's councillor councillor's councillors councils counsel counsel's counselings counselled counselling counsellor counsellor's counsellors counsels count countable countdown countdown's countdowns counted countenance countenance's countenanced countenances countenancing counter counter's counteract counteracted counteracting counteracts counterattack counterattack's counterattacked counterattacking counterattacks counterbalance counterbalance's counterbalanced counterbalances counterbalancing counterclockwise countered counterexample counterfeit counterfeited counterfeiter counterfeiter's counterfeiters counterfeiting counterfeits countering counterpart counterpart's counterparts counterproductive counters countersign countersigned countersigning countersigns countess countess's countesses counties counting countless countries country country's countryman countryman's countrymen countryside countryside's countrysides countrywoman countrywoman's countrywomen counts county county's coup coup's couple couple's coupled couples coupling coupling's coupon coupon's coupons coups courage courage's courageous courageously courier courier's couriered couriering couriers course course's coursed courser courses coursing court court's courted courteous courteously courtesies courtesy courtesy's courthouse courthouse's courthouses courting courtroom courtroom's courtrooms courts courtship courtship's courtships courtyard courtyard's courtyards cousin cousin's cousins cove cove's covenant covenant's covenanted covenanting covenants cover coverage coverage's coverall coveralls covered covering covering's coverings covers covers's covert covertly coverts coves covet coveted coveting covetous covets cow cow's coward coward's cowardice cowardice's cowardly cowards cowboy cowboy's cowboys cowed cower cowered cowering cowers cowgirl cowgirl's cowgirls cowhide cowhide's cowhides cowing coworker coworkers cows cox cox's coy coyer coyest coyote coyote's coyotes cozily coziness coziness's crab crab's crabbed crabbier crabbiest crabbing crabby crabs crack crackdown crackdown's crackdowns cracked cracker cracker's crackers cracking crackle crackled crackles crackling crackpot crackpot's crackpots cracks cradle cradle's cradled cradles cradling craft craft's crafted craftier craftiest craftily crafting crafts craftsman craftsman's craftsmanship craftsmanship's craftsmen crafty crag crag's craggier craggiest craggy crags cram crammed cramming cramp cramp's cramped cramping cramps crams cranberries cranberry cranberry's crane crane's craned cranes crania craning cranium cranium's craniums crank crank's cranked cranker crankest crankier crankiest cranking cranks cranky crannied crannies cranny cranny's crannying crap crap's crapped crappie crappier crappies crappiest crapping crappy craps crash crashed crashes crashing crass crasser crassest crate crate's crated crater crater's cratered cratering craters crates crating cravat cravat's cravats cravatted cravatting crave craved craves craving craving's cravings crawfish crawfish's crawfishes crawl crawled crawling crawls crayfish crayfish's crayfishes crayon crayon's crayoned crayoning crayons craze craze's crazed crazes crazier crazies craziest crazily craziness craziness's crazing crazy creak creaked creakier creakiest creaking creaks creaky cream cream's creamed creamier creamiest creaming creams creamy crease crease's creased creases creasing create created creates creating creation creation's creations creative creatively creativity creativity's creator creator's creators creature creature's creatures credence credence's credential credentials credibility credibility's credible credibly credit credit's creditable credited crediting creditor creditor's creditors credits credo credo's credos credulous creed creed's creeds creek creek's creeks creep creepier creepies creepiest creeping creeps creepy cremate cremated cremates cremating cremation cremation's cremations crematoria crematorium crematorium's crematoriums creole creole's creoles crepe crepe's crepes crept crescendi crescendo crescendo's crescendos crescent crescent's crescents crest crest's crested crestfallen cresting crests cretin cretin's cretinous cretins crevasse crevasse's crevasses crevice crevice's crevices crew crew's crewed crewing crews crib crib's cribbed cribbing cribs crick crick's cricked cricket cricket's crickets cricking cricks cried cries crime crime's crimed crimes criminal criminal's criminally criminals criming crimp crimped crimping crimps crimson crimson's crimsoned crimsoning crimsons cringe cringed cringes cringing crinkle crinkled crinkles crinklier crinklies crinkliest crinkling crinkly cripple cripple's crippled cripples crippling crises crisis crisis's crisp crisped crisper crispest crispier crispiest crisping crisply crisps crispy crisscross crisscrossed crisscrosses crisscrossing criteria criterion criterion's criterions critic critic's critical critically criticise criticised criticises criticising criticism criticism's criticisms critics critique critique's critiqued critiques critiquing critter critter's critters croak croaked croaking croaks crochet crocheted crocheting crochets croci crock crock's crockery crockery's crocks crocodile crocodile's crocodiles crocus crocus's crocuses crofts croissant croissant's croissants cronies crony crony's crook crook's crooked crookeder crookedest crooking crooks croon crooned crooner crooner's crooners crooning croons crop crop's cropped cropping crops croquet croquet's cross cross's crossbow crossbow's crossbows crosscheck crosschecked crosschecking crosschecks crossed crosser crosses crossest crossfire crossfire's crossfires crossing crossing's crossings crossover crossover's crossovers crossroad crossroads crossroads's crosstown crosswalk crosswalk's crosswalks crossword crosswords crotch crotch's crotches crouch crouched crouches crouching crow crow's crowbar crowbar's crowbars crowd crowd's crowded crowding crowds crowed crowing crown crown's crowned crowning crowns crows crucial crucially crucified crucifies crucifix crucifix's crucifixes crucifixion crucifixion's crucifixions crucify crucifying crud crud's cruddier cruddiest cruddy crude crudely cruder crudest crudity crudity's cruel crueler cruelest crueller cruellest cruelly cruels cruelties cruelty cruelty's cruise cruised cruiser cruiser's cruisers cruises cruising crumb crumb's crumbed crumbing crumble crumbled crumbles crumblier crumblies crumbliest crumbling crumbly crumbs crummier crummiest crummy crumple crumpled crumples crumpling crunch crunched crunches crunchier crunchiest crunching crunchy crusade crusade's crusaded crusader crusader's crusaders crusades crusading crush crushed crushes crushing crust crust's crustacean crustacean's crustaceans crusted crustier crusties crustiest crusting crusts crusty crutch crutch's crutches crux crux's cruxes cry crybabies crybaby crybaby's crying cryings crypt crypt's cryptic cryptically crypts crystal crystal's crystallisation crystallisation's crystallise crystallised crystallises crystallising crystals cs cs's cub cub's cube cube's cubed cubes cubic cubicle cubicle's cubicles cubing cubs cuckoo cuckoo's cuckoos cucumber cucumber's cucumbers cuddle cuddled cuddles cuddlier cuddliest cuddling cuddly cue cue's cued cueing cues cuff cuff's cuffed cuffing cuffs cuing cuisine cuisine's cuisines culinary cull culled culling culls culminate culminated culminates culminating culmination culmination's culminations culpability culpability's culpable culprit culprit's culprits cult cult's cultivate cultivated cultivates cultivating cultivation cultivation's cults cultural culturally culture culture's cultured cultures culturing cumbersome cumming cums cumulative cunning cunninger cunningest cunningly cup cup's cupboard cupboard's cupboards cupcake cupcake's cupcakes cupful cupful's cupfuls cupped cupping cups cupsful cur cur's curable curator curator's curators curb curb's curbed curbing curbs curd curd's curdle curdled curdles curdling curds cure cured cures curfew curfew's curfews curing curio curio's curios curiosities curiosity curiosity's curious curiouser curiousest curiously curl curled curler curler's curlers curlier curliest curling curling's curls curly currant currant's currants currencies currency currency's current currently currents curricula curriculum curriculum's curriculums curried curries curry curry's currying curse curse's cursed curseder cursedest curses cursing cursor cursor's cursored cursores cursoring cursors cursory curst curt curtail curtailed curtailing curtails curtain curtain's curtained curtaining curtains curter curtest curtsied curtsies curtsy curtsy's curtsying curvature curvature's curvatures curve curve's curved curved's curves curvier curviest curving curvy cushion cushion's cushioned cushioning cushions cuss cuss's cussed cusses cussing custard custard's custards custodial custodian custodian's custodians custody custody's custom custom's customarily customary customer customer's customers customisation customise customised customises customising customs cut cutback cutback's cutbacks cute cutely cuteness cuteness's cuter cutes cutest cuticle cuticle's cuticles cutlery cutlery's cutlet cutlet's cutlets cutoff cutoff's cutoffs cuts cutter cutter's cutters cutthroat cutthroat's cutthroats cutting cutting's cuttings cyanide cyanide's cybernetics cybernetics's cyberspace cycle cycle's cycled cycles cyclic cyclical cycling cycling's cyclist cyclist's cyclists cyclone cyclone's cyclones cylinder cylinder's cylinders cylindrical cymbal cymbal's cymbals cynic cynic's cynical cynically cynicism cynicism's cynics cypress cypress's cypresses cyst cyst's cysts d dab dabbed dabbing dabble dabbled dabbles dabbling dabs dachshund dachshund's dachshunds dad dad's daddies daddy daddy's dads daemon daemon's daffodil daffodil's daffodils daft dagger dagger's daggers dailies daily daintier dainties daintiest daintily dainty dairies dairy dairy's dais dais's daises daisies daisy daisy's dallied dallies dally dallying dam dam's damage damage's damaged damages damaging dame dame's dames dammed damming damn damnation damnation's damndest damned damneder damnedest damning damns damp damped dampen dampened dampening dampens damper damper's dampers dampest damping dampness dampness's damps dams damsel damsel's damsels dance danced dancer dancer's dancers dances dancing dandelion dandelion's dandelions dandier dandies dandiest dandruff dandruff's dandy dandy's danger danger's dangered dangering dangerous dangerously dangers dangle dangled dangles dangling dank danker dankest dapper dapperer dapperest dappers dare dared daredevil daredevil's daredevils dares daring dark darken darkened darkening darkens darker darkest darklier darkliest darkly darkness darkness's darkroom darkroom's darkrooms darling darling's darlings darn darned darneder darnedest darning darns dart dart's darted darting darts dash dashboard dashboard's dashboards dashed dashes dashing dastardly data data's database databased databases databasing date date's dated dates dating datum datum's daub daubed daubing daubs daughter daughter's daughters daunt daunted daunting dauntless daunts dawdle dawdled dawdles dawdling dawn dawn's dawned dawning dawns day day's daybreak daybreak's daydream daydream's daydreamed daydreamer daydreamer's daydreamers daydreaming daydreams daydreamt daylight daylight's days daytime daytime's daze dazed dazes dazing dazzle dazzled dazzles dazzling dazzlings deacon deacon's deaconess deaconess's deaconesses deacons dead deaden deadened deadening deadens deader deadest deadlier deadliest deadline deadline's deadlined deadlines deadlining deadlock deadlock's deadlocked deadlocking deadlocks deadly deadpan deadpanned deadpanning deadpans deaf deafen deafened deafening deafening's deafens deafer deafest deafness deafness's deal dealer dealer's dealers dealership dealership's dealerships dealing dealing's dealings deals dealt dean dean's deaned deaning deans dear dearer dearest dearly dears dearth dearth's dearths death death's deathbed deathbed's deathbeds deaths deathtrap deathtrap's deathtraps deaves debase debased debasement debasement's debasements debases debasing debatable debate debate's debated debates debating debaucheries debauchery debauchery's debilitate debilitated debilitates debilitating debilities debility debility's debit debit's debited debiting debits debonair debrief debriefed debriefing debriefings debriefs debris debris's debt debt's debtor debtor's debtors debts debug debugged debugger debugging debugs debunk debunked debunking debunks debut debut's debuted debuting debuts decade decade's decadence decadence's decadent decadents decades decaf decaffeinate decaffeinated decaffeinates decaffeinating decal decal's decals decanter decanter's decanters decapitate decapitated decapitates decapitating decathlon decathlon's decathlons decay decayed decaying decays decease deceased deceases deceasing deceit deceit's deceitful deceitfully deceitfulness deceitfulness's deceits deceive deceived deceives deceiving decencies decency decency's decent decenter decentest decently decentralisation decentralisation's decentralise decentralised decentralises decentralising deception deception's deceptions deceptive deceptively decibel decibel's decibels decide decided decidedly decides deciding deciduous decimal decimal's decimals decimate decimated decimates decimating decipher deciphered deciphering deciphers decision decision's decisions decisive decisively deck deck's decked decking decks declaration declaration's declarations declare declared declares declaring declension declension's decline declined declines declining decode decoded decoder decoder's decodes decoding decompose decomposed decomposes decomposing decomposition decomposition's decor decorate decorated decorates decorating decoration decoration's decorations decorative decorator decorator's decorators decorous decors decorum decorum's decoy decoy's decoyed decoying decoys decrease decreased decreases decreasing decree decree's decreed decreeing decrees decrepit decried decries decriminalise decriminalised decriminalises decriminalising decry decrying dedicate dedicated dedicates dedicating dedication dedication's dedications deduce deduced deduces deducing deduct deducted deductible deductibles deducting deduction deduction's deductions deductive deducts deed deed's deeded deeding deeds deem deemed deeming deems deep deepen deepened deepening deepens deeper deepest deeply deeps deer deer's deers deface defaced defaces defacing defamation defamation's defamatory defame defamed defames defaming default default's defaulted defaulting defaults defeat defeated defeating defeatist defeatist's defeatists defeats defecate defecated defecates defecating defect defect's defected defecting defection defection's defections defective defectives defector defector's defectors defects defence defence's defenced defenceless defences defencing defencive defend defendant defendant's defendants defended defender defender's defenders defending defends defensible defensively defer deference deference's deferential deferred deferring defers defiance defiance's defiant defiantly deficiencies deficiency deficiency's deficient deficit deficit's deficits defied defies defile defiled defiles defiling definable define defined defines defining definite definitely definition definition's definitions definitive definitively deflate deflated deflates deflating deflation deflation's deflect deflected deflecting deflection deflection's deflections deflects deforestation deforestation's deform deformation deformation's deformations deformed deforming deformities deformity deformity's deforms defraud defrauded defrauding defrauds defrost defrosted defrosting defrosts deft defter deftest deftly defunct defuncts defuse defused defuses defusing defy defying degenerate degenerated degenerates degenerating degeneration degeneration's degradation degradation's degrade degraded degrades degrading degree degree's degrees dehydrate dehydrated dehydrates dehydrating dehydration dehydration's deified deifies deify deifying deign deigned deigning deigns deities deity deity's deject dejected dejectedly dejecting dejection dejection's dejects delay delayed delaying delays delectable delegate delegate's delegated delegates delegating delegation delegation's delegations delete deleted deleterious deletes deleting deletion deletion's deletions deli deli's deliberate deliberated deliberately deliberates deliberating deliberation deliberation's deliberations delicacies delicacy delicacy's delicate delicately delicatessen delicatessen's delicatessens delicious deliciously delight delighted delightful delightfully delighting delights delimit delimited delimiter delimiters delimiting delimits delineate delineated delineates delineating delinquencies delinquency delinquency's delinquent delinquent's delinquents deliria delirious deliriously delirium delirium's deliriums delis deliver deliverance deliverance's delivered deliveries delivering delivers delivery delivery's delta delta's deltas delude deluded deludes deluding deluge deluge's deluged deluges deluging delusion delusion's delusions deluxe delve delved delves delving demagogic demagogue demagogue's demagogues demand demanded demanding demands demean demeaned demeaning demeanour demeanour's demeans demented dementia dementia's demerit demerit's demerited demeriting demerits demise demise's demised demises demising demo demo's democracies democracy democracy's democrat democrat's democratic democratically democrats demoed demographic demographics demoing demolish demolished demolishes demolishing demolition demolition's demolitions demon demon's demonic demons demonstrably demonstrate demonstrated demonstrates demonstrating demonstration demonstration's demonstrations demonstrative demonstratives demonstrator demonstrator's demonstrators demoralise demoralised demoralises demoralising demos demote demoted demotes demoting demotion demotion's demotions demount demure demurely demurer demurest den den's denial denial's denials denied denies denigrate denigrated denigrates denigrating denim denim's denims denomination denomination's denominations denominator denominator's denominators denote denoted denotes denoting denounce denounced denounces denouncing dens dense densely denser densest densities density density's dent dent's dental dented denting dentist dentist's dentistry dentistry's dentists dents denture dentures denunciation denunciation's denunciations deny denying deodorant deodorant's deodorants deodorise deodorised deodorises deodorising depart departed departing department department's departmental departments departs departure departure's departures depend dependable dependant dependant's dependants depended dependence dependence's dependencies dependency dependency's dependent dependent's dependents depending depends depict depicted depicting depiction depiction's depicts deplete depleted depletes depleting depletion depletion's deplorable deplorably deplore deplored deplores deploring deploy deployed deploying deployment deployment's deployments deploys deport deportation deportation's deportations deported deporting deportment deportment's deports depose deposed deposes deposing deposit deposited depositing deposits depot depot's depots deprave depraved depraves depraving depravities depravity depravity's deprecate deprecated deprecates deprecating depreciate depreciated depreciates depreciating depreciation depreciation's depress depressed depresses depressing depressingly depression depression's depressions deprivation deprivation's deprivations deprive deprived deprives depriving depth depth's depths deputies deputy deputy's derail derailed derailing derailment derailment's derailments derails derange deranged deranges deranging derbies derby derby's derelict derelicts deres deride derided derides deriding derision derision's derivation derivation's derivations derivative derivatives derive derived derives deriving derogatory derrick derrick's derricks descend descendant descendant's descendants descended descending descends descent descent's descents describable describe described describes describing description description's descriptions descriptive descriptor descriptors desecrate desecrated desecrates desecrating desecration desecration's desegregate desegregated desegregates desegregating desegregation desegregation's desert desert's deserted deserter deserter's deserters deserting deserts deserve deserved deserves deserving deservings design designate designated designates designating designation designation's designations designed designer designer's designers designing designs desirability desirability's desirable desire desired desires desiring desirous desist desisted desisting desists desk desk's desks desktop desktops desolate desolated desolates desolating desolation desolation's despair despaired despairing despairs despatch despatched despatches despatching desperate desperately desperation desperation's despicable despise despised despises despising despite despondent despondently despot despot's despotic despots dessert dessert's desserts destabilise destination destination's destinations destine destined destines destinies destining destiny destiny's destitute destitution destitution's destroy destroyed destroyer destroyer's destroyers destroying destroys destruction destruction's destructive detach detachable detached detaches detaching detachment detachment's detachments detail detail's detailed detailing details detain detained detaining detains detect detectable detected detecting detection detection's detective detective's detectives detector detector's detectors detects detentes detention detention's detentions deter detergent detergent's detergents deteriorate deteriorated deteriorates deteriorating deterioration deterioration's determinable determination determination's determinations determine determined determiner determiner's determiners determines determining determinism determinism's deterministic deterred deterrence deterrence's deterrent deterrent's deterrents deterring deters detest detested detesting detests dethrone dethroned dethrones dethroning detonate detonated detonates detonating detonation detonation's detonations detonator detonator's detonators detour detour's detoured detouring detours detox detoxed detoxes detoxing detract detracted detracting detracts detriment detriment's detrimental detriments devaluation devaluation's devaluations devalue devalued devalues devaluing devastate devastated devastates devastating devastation devastation's develop developed developer developer's developers developing development development's developments develops deviant deviants deviate deviated deviates deviating deviation deviation's deviations device device's devices devil devil's devilish devilled devilling devils devious devise devised devises devising devoid devolution devolution's devolve devolved devolves devolving devote devoted devotedly devotee devotee's devotees devotes devoting devotion devotion's devotions devour devoured devouring devours devout devouter devoutest devoutly dew dew's dexterity dexterity's dexterous diabetes diabetes's diabetic diabetics diabolical diagnose diagnosed diagnoses diagnosing diagnosis diagnosis's diagnostic diagnostics diagnostics's diagonal diagonally diagonals diagram diagram's diagramed diagraming diagrammed diagramming diagrams dial dial's dialect dialect's dialects dialled dialling diallings dialog dialogs dialogue dialogue's dialogues dials diameter diameter's diameters diametrically diamond diamond's diamonds diaper diaper's diapered diapering diapers diaphragm diaphragm's diaphragms diaries diarrhoea diarrhoea's diary diary's diatribe diatribe's dice diced dices dicey dichotomies dichotomy dichotomy's dicier diciest dicing dick dick's dicks dictate dictated dictates dictating dictation dictation's dictations dictator dictator's dictatorial dictators dictatorship dictatorship's dictatorships diction diction's dictionaries dictionary dictionary's did didn't die died diehard diehards dieing dies dies's diesel diesel's dieseled dieseling diesels diet diet's dietaries dietary dieted dieting diets differ differed difference difference's differences different differential differentiate differentiated differentiates differentiating differentiation differentiation's differently differing differs difficult difficulties difficulty difficulty's diffuse diffused diffuses diffusing diffusion diffusion's dig digest digested digestible digesting digestion digestion's digestions digestive digests digger digging digit digit's digital digitally digitise digitised digitises digitising digits dignified dignifies dignify dignifying dignitaries dignitary dignitary's dignities dignity dignity's digress digressed digresses digressing digression digression's digressions digs dike dike's dikes dilapidated dilapidation dilapidation's dilate dilated dilates dilating dilation dilation's dilemma dilemma's dilemmas diligence diligence's diligent diligently dill dill's dilled dilling dills dilute diluted dilutes diluting dilution dilution's dim dime dime's dimension dimension's dimensional dimensions dimer dimes diminish diminished diminishes diminishing diminutive diminutives dimly dimmed dimmer dimmest dimming dimple dimple's dimpled dimples dimpling dims din din's dine dined diner diner's diners dines dinghies dinghy dinghy's dingier dingies dingiest dingy dining dinned dinner dinner's dinnered dinnering dinners dinning dinosaur dinosaur's dinosaurs dins diocese diocese's dioceses dioxide dioxide's dip diphtheria diphtheria's diphthong diphthong's diphthongs diploma diploma's diplomacy diplomacy's diplomas diplomat diplomat's diplomata diplomatic diplomatically diplomatics diplomats dipped dipping dips dipstick dipstick's dipsticks dire direct directed directer directest directing direction direction's directions directive directive's directives directly directness directness's director director's directories directors directory directory's directs direr direst dirge dirge's dirges dirt dirt's dirtied dirtier dirties dirtiest dirty dirtying dis dis's disabilities disability disability's disable disabled disables disabling disadvantage disadvantage's disadvantaged disadvantageous disadvantages disadvantaging disaffect disaffected disaffecting disaffects disagree disagreeable disagreeably disagreed disagreeing disagreement disagreement's disagreements disagrees disallow disallowed disallowing disallows disambiguate disappear disappearance disappearance's disappearances disappeared disappearing disappears disappoint disappointed disappointing disappointingly disappointment disappointment's disappointments disappoints disapproval disapproval's disapprove disapproved disapproves disapproving disapprovingly disarm disarmament disarmament's disarmed disarming disarms disarray disarray's disarrayed disarraying disarrays disaster disaster's disasters disastrous disastrously disavow disavowal disavowal's disavowals disavowed disavowing disavows disband disbanded disbanding disbands disbelief disbelief's disbelieve disbelieved disbelieves disbelieving disburse disbursed disbursement disbursement's disbursements disburses disbursing disc disc's discard discarded discarding discards discern discerned discernible discerning discerns discharge discharged discharges discharging disciple disciple's disciples disciplinarian disciplinarian's disciplinarians disciplinary discipline discipline's disciplined disciplines disciplining disclaim disclaimed disclaimer disclaimer's disclaimers disclaiming disclaims disclose disclosed discloses disclosing disclosure disclosure's disclosures disco disco's discoed discoing discolour discolouration discolouration's discolourations discoloured discolouring discolours discomfort discomfort's discomforted discomforting discomforts disconcert disconcerted disconcerting disconcerts disconnect disconnected disconnecting disconnection disconnection's disconnections disconnects disconsolate disconsolately discontent discontent's discontented discontenting discontents discontinuation discontinuation's discontinuations discontinue discontinued discontinues discontinuing discontinuity discontinuity's discord discord's discordant discorded discording discords discos discount discounted discounting discounts discourage discouraged discouragement discouragement's discouragements discourages discouraging discourse discourse's discoursed discourses discoursing discourteous discourtesies discourtesy discourtesy's discover discovered discoverer discoverer's discoverers discoveries discovering discovers discovery discovery's discredit discredited discrediting discredits discreet discreeter discreetest discreetly discrepancies discrepancy discrepancy's discrete discretion discretion's discretionary discriminate discriminated discriminates discriminating discrimination discrimination's discriminatory discs discus discus's discuses discuss discussed discusses discussing discussion discussion's discussions disdain disdain's disdained disdainful disdaining disdains disease disease's diseased diseases disembark disembarkation disembarkation's disembarked disembarking disembarks disenchant disenchanted disenchanting disenchantment disenchantment's disenchants disenfranchise disenfranchised disenfranchises disenfranchising disengage disengaged disengages disengaging disentangle disentangled disentangles disentangling disfavour disfavour's disfavoured disfavouring disfavours disfigure disfigured disfigurement disfigurement's disfigurements disfigures disfiguring disgrace disgrace's disgraced disgraceful disgracefully disgraces disgracing disgruntle disgruntled disgruntles disgruntling disguise disguised disguises disguising disgust disgusted disgusting disgustingly disgusts dish dish's dishearten disheartened disheartening disheartens dished dishes dishevel dishevelled dishevelling dishevels dishing dishonest dishonestly dishonesty dishonesty's dishonour dishonourable dishonourably dishonoured dishonouring dishonours dishtowel dishtowel's dishtowels dishwasher dishwasher's dishwashers disillusion disillusioned disillusioning disillusionment disillusionment's disillusions disincentive disincentive's disinfect disinfectant disinfectant's disinfectants disinfected disinfecting disinfects disingenuous disinherit disinherited disinheriting disinherits disintegrate disintegrated disintegrates disintegrating disintegration disintegration's disinterest disinterest's disinterested disinterests disjoint disjointed disjointing disjoints disk disk's diskette diskettes disks dislike disliked dislikes disliking dislocate dislocated dislocates dislocating dislocation dislocation's dislocations dislodge dislodged dislodges dislodging disloyal disloyalty disloyalty's dismal dismaler dismalest dismaller dismallest dismally dismantle dismantled dismantles dismantling dismay dismayed dismaying dismays dismember dismembered dismembering dismembers dismiss dismissal dismissal's dismissals dismissed dismisses dismissing dismissive dismount dismounted dismounting dismounts disobedience disobedience's disobedient disobey disobeyed disobeying disobeys disorder disorder's disordered disordering disorderly disorders disorganisation disorganisation's disorganise disorganised disorganises disorganising disorient disorientation disorientation's disoriented disorienting disorients disown disowned disowning disowns disparage disparaged disparages disparaging disparate disparates disparities disparity disparity's dispassionate dispassionately dispatch dispatched dispatches dispatching dispel dispelled dispelling dispels dispensable dispensaries dispensary dispensary's dispensation dispensation's dispensations dispense dispensed dispenser dispenser's dispensers dispenses dispensing dispersal dispersal's disperse dispersed disperses dispersing dispersion dispersion's dispirit dispirited dispiriting dispirits displace displaced displacement displacement's displacements displaces displacing display displayed displaying displays displease displeased displeases displeasing displeasure displeasure's disposable disposables disposal disposal's disposals dispose disposed disposes disposing disposition disposition's dispositions dispossess dispossessed dispossesses dispossessing disproportionate disproportionated disproportionately disproportionates disproportionating disprove disproved disproven disproves disproving dispute disputed disputes disputing disqualification disqualification's disqualifications disqualified disqualifies disqualify disqualifying disquiet disquiet's disquieted disquieting disquiets disregard disregarded disregarding disregards disrepair disrepair's disreputable disrepute disrepute's disrespect disrespect's disrespected disrespectful disrespectfully disrespecting disrespects disrupt disrupted disrupting disruption disruption's disruptions disruptive disrupts diss dissatisfaction dissatisfaction's dissatisfied dissatisfies dissatisfy dissatisfying dissect dissected dissecting dissection dissection's dissections dissects dissed disseminate disseminated disseminates disseminating dissemination dissemination's dissension dissension's dissensions dissent dissented dissenter dissenter's dissenters dissenting dissents dissertation dissertation's dissertations disservice disservice's disservices disses dissidence dissidence's dissident dissidents dissimilar dissimilarities dissimilarity dissimilarity's dissimilars dissing dissipate dissipated dissipates dissipating dissipation dissipation's dissociate dissociated dissociates dissociating dissociation dissociation's dissolute dissolutes dissolution dissolution's dissolve dissolved dissolves dissolving dissonance dissonance's dissonances dissuade dissuaded dissuades dissuading distance distance's distanced distances distancing distant distantly distaste distaste's distasteful distastefully distastes distend distended distending distends distention distention's distentions distil distill distillation distillation's distillations distilled distiller distiller's distilleries distillers distillery distillery's distilling distills distils distinct distincter distinctest distinction distinction's distinctions distinctive distinctively distinctly distinguish distinguishable distinguished distinguishes distinguishing distort distorted distorter distorter's distorting distortion distortion's distortions distorts distract distracted distracting distraction distraction's distractions distracts distraught distress distressed distresses distressing distressingly distribute distributed distributes distributing distribution distribution's distributions distributor distributor's distributors district district's districts distrust distrusted distrustful distrustfully distrusting distrusts disturb disturbance disturbance's disturbances disturbed disturbing disturbs disuse disuse's disused disuses disusing ditch ditch's ditched ditches ditching dither dithered dithering dithers ditties ditto ditto's dittoed dittoes dittoing dittos ditty ditty's dive dived dived's diver diver's diverge diverged divergence divergence's divergences divergent diverges diverging divers diverse diversification diversification's diversified diversifies diversify diversifying diversion diversion's diversions diversities diversity diversity's divert diverted diverting diverts dives divest divested divesting divests divide divided dividend dividend's dividends divider divider's dividers divides dividing divine divined divinely diviner divines divinest diving divining divinities divinity divinity's divisible division division's divisions divisive divisor divisor's divisors divorce divorce's divorced divorces divorcing divorce divorce's divorces divulge divulged divulges divulging dizzied dizzier dizzies dizziest dizziness dizziness's dizzy dizzying do docile dock dock's docked docket docket's docketed docketing dockets docking docks doctor doctor's doctorate doctorate's doctorates doctored doctoring doctors doctrine doctrine's doctrines document document's documentaries documentary documentation documentation's documented documenting documents dodge dodged dodges dodging dodo dodo's doe doe's doer doer's doers does doesn't doest dog dog's dogged doggedly doggerel doggerel's dogging doggone doggoned doggoner doggones doggonest doggoning doghouse doghouse's doghouses dogma dogma's dogmas dogmata dogmatic dogmatics dogs dogwood dogwood's dogwoods doilies doily doily's doing doing's doldrums doldrums's dole dole's doled doleful dolefuller dolefullest dolefully doles doling doll doll's dollar dollar's dollars dolled dollhouse dollhouse's dollhouses dollies dolling dollop dollop's dolloped dolloping dollops dolls dolly dolly's dolphin dolphin's dolphins domain domain's domains dome dome's domed domes domestic domesticate domesticated domesticates domesticating domesticity domesticity's domestics domicile domicile's domiciled domiciles domiciling dominance dominance's dominant dominants dominate dominated dominates dominating domination domination's domineer domineered domineering domineers doming dominion dominion's dominions domino domino's dominoes dominos don don't donate donated donates donating donation donation's donations done donkey donkey's donkeys donor donor's donors dons donut donuts doodad doodad's doodads doodle doodled doodles doodling doohickey doohickey's doohickeys doom doom's doomed dooming dooms doomsday doomsday's door door's doorbell doorbell's doorbells doored dooring doorknob doorknob's doorknobs doorman doorman's doormat doormat's doormats doormen doors doorstep doorstep's doorstepped doorstepping doorsteps doorway doorway's doorways dope dope's doped dopes dopey dopier dopiest doping dopy dork dorkier dorkiest dorks dorky dorm dorm's dormant dormants dormitories dormitory dormitory's dorms dorsal dorsals dos dosage dosage's dosages dose dose's dosed doses dosing dosses dossier dossier's dossiers dot dot's dote doted dotes doting dotings dots dotted dotting double doubled doubles doubles's doubling doubly doubt doubt's doubted doubtful doubtfully doubting doubtless doubts dough dough's doughnut doughnut's doughnuts doughnutted doughnutting dour dourer dourest douse doused douses dousing dove dove's doves dowdier dowdies dowdiest dowdy down downcast downed downer downer's downers downfall downfall's downfalls downgrade downgraded downgrades downgrading downhearted downhill downhills downier downiest downing download downloaded downloading downloads downplay downplayed downplaying downplays downpour downpour's downpours downright downs downsize downsized downsizes downsizing downstairs downstate downstream downtime downtime's downtown downtown's downtrodden downturn downturn's downturns downward downwards downwind downy dowries dowry dowry's doze dozed dozen dozens dozes dozing drab drabber drabbest drabs draconian draft draft's drafted drafting drafts drag drag's dragged dragging dragon dragon's dragonflies dragonfly dragonfly's dragons drags drain drain's drainage drainage's drained draining drains drake drake's drakes drama drama's dramas dramatic dramatically dramatics dramatics's dramatisation dramatisation's dramatisations dramatise dramatised dramatises dramatising dramatist dramatist's dramatists drank drape draped draperies drapery drapery's drapes draping drastic drastically draught draught's draughted draughtier draughtiest draughting draughts draughtsman draughtsman's draughtsmen draughty draw drawback drawback's drawbacks drawbridge drawbridge's drawbridges drawer drawer's drawers drawing drawing's drawings drawl drawled drawling drawls drawn draws dread dreaded dreadful dreadfully dreading dreadlocks dreads dream dream's dreamer dreamer's dreamers dreamier dreamiest dreaming dreams dreamt dreamy drearier drearies dreariest dreary dredge dredge's dredged dredges dredging drees dregs drench drenched drenches drenching dress dressed dresser dresser's dressers dresses dressier dressiest dressing dressing's dressings dressmaker dressmaker's dressmakers dressy drew dribble dribbled dribbles dribbling dried drier driers dries driest drift drifted drifter drifter's drifters drifting drifts driftwood driftwood's drill drill's drilled drilling drills drink drinkable drinker drinker's drinkers drinking drinkings drinks drip dripped dripping dripping's drips drive drivel drivelled drivelling drivels driven driver driver's drivers drives driveway driveway's driveways driving drivings drizzle drizzle's drizzled drizzles drizzling droll droller drollest drone drone's droned drones droning drool drooled drooling drools droop drooped drooping droops drop drop's dropout dropout's dropouts dropped dropping dropping's droppings drops dross dross's drought drought's droughts drove droves drown drowned drowning drownings drowns drowse drowsed drowses drowsier drowsiest drowsily drowsiness drowsiness's drowsing drowsy drudge drudge's drudged drudgery drudgery's drudges drudging drug drug's drugged drugging druggist druggist's druggists drugs drugstore drugstore's drugstores drum drum's drummed drummer drummer's drummers drumming drums drumstick drumstick's drumsticks drunk drunkard drunkard's drunkards drunken drunkenly drunkenness drunkenness's drunker drunkest drunks dry dryer dryer's dryers drying dryly dryness dryness's drys dual dualism dualism's dub dubbed dubbing dubious dubiously dubs duchess duchess's duchesses duck duck's ducked ducking duckling duckling's ducks duct duct's ducts dud dud's dude dude's duded dudes duding duds due due's duel duel's duelled duelling duellings duels dues duet duet's duets duff duff's dug dugout dugout's dugouts duke duke's duked dukes duking dull dulled duller dullest dulling dullness dullness's dulls dully duly dumb dumbbell dumbbell's dumbbells dumbed dumber dumbest dumbfound dumbfounded dumbfounding dumbfounds dumbing dumbs dummies dummy dummy's dump dumped dumpier dumpies dumpiest dumping dumpling dumpling's dumps dumpster dumpy dunce dunce's dunces dune dune's dunes dung dung's dunged dungeon dungeon's dungeoned dungeoning dungeons dunging dungs dunk dunked dunking dunks dunno dunno's duo duo's duos dupe dupe's duped dupes duping duplex duplex's duplexes duplicate duplicated duplicates duplicating duplication duplication's duplicity duplicity's durability durability's durable duration duration's duress duress's during dusk dusk's duskier duskiest dusky dust dust's dustbin dustbin's dusted dustier dustiest dusting dustmen dustpan dustpan's dustpans dusts dusty duties dutiful dutifully duty duty's duvet duvet's dwarf dwarf's dwarfed dwarfer dwarfest dwarfing dwarfs dwarves dwell dwelled dweller dweller's dwellers dwelling dwelling's dwellings dwells dwelt dwindle dwindled dwindles dwindling dye dye's dyed dyeing dyes dying dyke dyke's dykes dynamic dynamical dynamically dynamics dynamics's dynamism dynamism's dynamite dynamite's dynamited dynamites dynamiting dynamo dynamo's dynamos dynasties dynasty dynasty's dysentery dysentery's dysfunction dysfunction's dysfunctional dysfunctions dyslexia dyslexia's dyslexic dyslexics dbutante dbutante's dbutantes dtente e each eager eager's eagerer eagerest eagerly eagerness eagerness's eagle eagle's eagles ear ear's earache earache's earaches eardrum eardrum's eardrums earl earl's earlier earliest earlobe earlobes earls early earmark earmarked earmarking earmarks earmuff earmuffs earn earned earner earner's earners earnest earnestly earnestness earnestness's earnests earning earning's earnings earns earphone earphones earplug earplug's earplugs earring earring's earrings ears earshot earshot's earsplitting earth earth's earthed earthier earthiest earthiness earthiness's earthing earthlier earthliest earthly earthquake earthquake's earthquaked earthquakes earthquaking earths earthshaking earthworm earthworm's earthworms earthy earwax earwax's ease ease's eased easel easel's easels eases easier easies easiest easily easing east east's eastbound easterlies easterly eastern easterner easterner's easterners eastward eastwards easy easygoing eat eaten eater eater's eateries eaters eatery eatery's eating eating's eats eave eaves eavesdrop eavesdropped eavesdropper eavesdropper's eavesdroppers eavesdropping eavesdrops ebb ebbed ebbing ebbs ebonies ebony ebony's ebullience ebullience's ebullient eccentric eccentricities eccentricity eccentricity's eccentrics ecclesiastical echo echo's echoed echoes echoing echos eclectic eclipse eclipse's eclipsed eclipses eclipsing ecological ecologically ecologist ecologist's ecologists ecology ecology's economic economical economically economics economics's economies economise economised economises economising economist economist's economists economy economy's ecosystem ecosystem's ecosystems ecstasies ecstasy ecstasy's ecstatic ecumenical eczema eczema's eddied eddies eddy eddy's eddying edge edge's edged edger edges edgeways edgewise edgier edgiest edging edgy edible edibles edict edict's edicts edification edification's edifice edifice's edifices edified edifies edify edifying edit edited editing edition edition's editions editor editor's editorial editorials editors editorship editorship's edits educate educated educates educating education education's educational educationally educations educator educator's educators eel eel's eels eerie eerier eeriest eerily eery effect effect's effected effecting effective effectively effectiveness effectiveness's effects effectual effeminate effervescence effervescence's effervescent efficiency efficiency's efficient efficiently efficients effigies effigy effigy's effort effort's effortless effortlessly efforts effusive effusively egalitarian egalitarianism egalitarianism's egalitarians egg egg's egged egghead egghead's eggheads egging eggplant eggplant's eggplants eggs eggshell eggshell's eggshells ego ego's egocentric egocentrics egoism egoism's egos egotism egotism's egotist egotist's egotistical egotists egregious egregiously eh eigenvalue eigenvalue's eight eight's eighteen eighteen's eighteens eighteenth eighteenths eighth eighths eighties eightieth eightieths eights eighty eighty's either ejaculate ejaculated ejaculates ejaculating ejaculation ejaculation's ejaculations eject ejected ejecting ejection ejection's ejections ejects eke eked ekes eking elaborate elaborated elaborately elaborates elaborating elaboration elaboration's elaborations elapse elapsed elapses elapsing elastic elasticity elasticity's elastics elate elated elates elating elation elation's elbow elbow's elbowed elbowing elbowroom elbowroom's elbows elder elderly elders eldest elect elected electing election election's elections elective electives elector elector's electoral electorate electorate's electorates electors electric electrical electrically electrician electrician's electricians electricity electricity's electrified electrifies electrify electrifying electrocute electrocuted electrocutes electrocuting electrocution electrocution's electrocutions electrode electrode's electrodes electrolysis electrolysis's electromagnetic electron electron's electronic electronically electronics electronics's electrons electrostatic elects elegance elegance's elegant elegantly elegies elegy elegy's element element's elemental elementary elements elephant elephant's elephants elevate elevated elevates elevating elevation elevation's elevations elevator elevator's elevators eleven eleven's elevens eleventh elevenths elf elf's elfin elicit elicited eliciting elicits eligibility eligibility's eligible eliminate eliminated eliminates eliminating elimination elimination's eliminations elite elite's elites elitism elitism's elitist elitist's elitists elk elk's elks ellipse ellipse's ellipses ellipsis elliptic elliptical elm elm's elms elongate elongated elongates elongating elope eloped elopement elopement's elopements elopes eloping eloquence eloquence's eloquent eloquently else elsewhere elucidate elucidated elucidates elucidating elude eluded eludes eluding elusive elves elves's em em's emaciate emaciated emaciates emaciating email email's emailed emailing emails emanate emanated emanates emanating emancipate emancipated emancipates emancipating emancipation emancipation's embalm embalmed embalming embalms embankment embankment's embankments embargo embargo's embargoed embargoes embargoing embark embarked embarking embarks embarrass embarrassed embarrasses embarrassing embarrassingly embarrassment embarrassment's embarrassments embassies embassy embassy's embattled embed embedded embedding embeds embellish embellished embellishes embellishing embellishment embellishment's embellishments ember ember's embers embezzle embezzled embezzlement embezzlement's embezzler embezzler's embezzlers embezzles embezzling embitter embittered embittering embitters emblazon emblazoned emblazoning emblazons emblem emblem's emblems embodied embodies embodiment embodiment's embody embodying emboss embossed embosses embossing embrace embraced embraces embracing embroider embroidered embroideries embroidering embroiders embroidery embroidery's embroil embroiled embroiling embroils embryo embryo's embryonic embryos emcee emcee's emceed emceeing emcees emerald emerald's emeralds emerge emerged emergence emergence's emergencies emergency emergency's emergent emerges emerging emeritus emigrant emigrant's emigrants emigrate emigrated emigrates emigrating emigration emigration's emigrations eminence eminence's eminences eminent eminently emir emir's emirate emirate's emirates emirs emissaries emissary emissary's emission emission's emissions emit emits emitted emitting emotion emotion's emotional emotionally emotions emotive empathise empathised empathises empathising empathy empathy's emperor emperor's emperors emphases emphasis emphasis's emphasise emphasised emphasises emphasising emphatic emphatically emphysema emphysema's empire empire's empires empirical employ employed employee employee's employees employer employer's employers employing employment employment's employments employs emporia emporium emporium's emporiums empower empowered empowering empowerment empowerment's empowers empress empress's empresses emptied emptier empties emptiest emptiness emptiness's empty emptying emulate emulated emulates emulating emulation emulation's emulations emulator emulator's emulators emulsion emulsion's emulsions enable enabled enables enabling enact enacted enacting enactment enactment's enactments enacts enamel enamel's enamelled enamelling enamellings enamels enamour enamoured enamouring enamours encapsulate encapsulated encapsulates encapsulating encase encased encases encasing enchant enchanted enchanting enchantment enchantment's enchantments enchants enchilada enchilada's enchiladas encircle encircled encircles encircling enclave enclave's enclaves enclose enclosed encloses enclosing enclosure enclosure's enclosures encode encoded encodes encoding encompass encompassed encompasses encompassing encore encored encores encoring encounter encountered encountering encounters encourage encouraged encouragement encouragement's encouragements encourages encouraging encroach encroached encroaches encroaching encrypted encryption encryption's encumber encumbered encumbering encumbers encumbrance encumbrance's encumbrances encyclopaedia encyclopaedias encyclopedia encyclopedia's encyclopedias end end's endanger endangered endangering endangers endear endeared endearing endearment endearment's endearments endears endeavour endeavoured endeavouring endeavours ended endemic endemics ending ending's endings endive endive's endives endless endlessly endorse endorsed endorsement endorsement's endorsements endorses endorsing endow endowed endowing endowment endowment's endowments endows ends endurance endurance's endure endured endures enduring endways enema enema's enemas enemata enemies enemy enemy's energetic energetically energetics energies energise energised energises energising energy energy's enforce enforceable enforced enforcement enforcement's enforces enforcing enfranchise enfranchised enfranchises enfranchising engage engaged engagement engagement's engagements engages engaging engender engendered engendering engenders engine engine's engined engineer engineer's engineered engineering engineering's engineers engines engining engrave engraved engraver engraver's engravers engraves engraving engraving's engravings engross engrossed engrosses engrossing engulf engulfed engulfing engulfs enhance enhanced enhancement enhancement's enhancements enhances enhancing enigma enigma's enigmas enigmatic enjoy enjoyable enjoyed enjoying enjoyment enjoyment's enjoyments enjoys enlarge enlarged enlargement enlargement's enlargements enlarges enlarging enlighten enlightened enlightening enlightenment enlightenment's enlightens enlist enlisted enlisting enlistment enlistment's enlistments enlists enliven enlivened enlivening enlivens enmities enmity enmity's enormities enormity enormity's enormous enormously enough enquire enquired enquires enquiries enquiring enquiry enquiry's enrage enraged enrages enraging enrich enriched enriches enriching enrichment enrichment's enrol enrolled enrolling enrolment enrolment's enrolments enrols ensconce ensconced ensconces ensconcing ensemble ensemble's ensembles enshrine enshrined enshrines enshrining ensign ensign's ensigns enslave enslaved enslaves enslaving ensue ensued ensues ensuing ensure ensured ensures ensuring entail entailed entailing entails entangle entangled entanglement entanglement's entanglements entangles entangling enter entered entering enterprise enterprise's enterprises enterprising enters entertain entertained entertainer entertainer's entertainers entertaining entertainment entertainment's entertainments entertains enthral enthralled enthralling enthrals enthuse enthused enthuses enthusiasm enthusiasm's enthusiasms enthusiast enthusiast's enthusiastic enthusiastically enthusiasts enthusing entice enticed enticement enticement's enticements entices enticing enticings entire entirely entirety entirety's entities entitle entitled entitlement entitlement's entitlements entitles entitling entity entity's entomologist entomologists entomology entomology's entourage entourage's entourages entrails entrance entrance's entranced entrances entrancing entrant entrant's entrants entrap entrapment entrapment's entrapped entrapping entraps entreat entreated entreaties entreating entreats entreaty entreaty's entrench entrenched entrenches entrenching entrepreneur entrepreneur's entrepreneurial entrepreneurs entries entropy entropy's entrust entrusted entrusting entrusts entry entry's entryway entryway's entryways entre entres entwine entwined entwines entwining enumerate enumerated enumerates enumerating enumeration enumeration's enunciate enunciated enunciates enunciating enunciation enunciation's envelop envelope envelope's enveloped envelopes enveloping envelops enviable envied envies envious enviously environment environment's environmental environmentalist environmentalist's environmentalists environmentally environments environs envisage envisaged envisages envisaging envision envisioned envisioning envisions envoy envoy's envoys envy envy's envying enzyme enzyme's enzymes eon eon's eons epaulet epaulet's epaulets ephemeral epic epic's epicentre epicentre's epicentres epics epidemic epidemics epidermis epidermis's epidermises epigram epigram's epigrams epilepsy epilepsy's epileptic epileptics epilogue epilogue's epilogued epilogues epiloguing episode episode's episodes episodic epistle epistle's epistles epitaph epitaph's epitaphs epithet epithet's epithets epitome epitome's epitomes epitomise epitomised epitomises epitomising epoch epoch's epochs epsilon epsilon's equal equalise equalised equalises equalising equality equality's equalled equalling equally equals equanimity equanimity's equate equated equates equating equation equation's equations equator equator's equatorial equators equestrian equestrians equilateral equilaterals equilibrium equilibrium's equine equines equinox equinox's equinoxes equip equipment equipment's equipped equipping equips equitable equities equity equity's equivalence equivalence's equivalences equivalent equivalently equivalents equivocal era era's eradicate eradicated eradicates eradicating eradication eradication's eras erase erased eraser eraser's erasers erases erasing erasure erasure's erect erected erecting erection erection's erections erects ergo ergonomic erode eroded erodes eroding erosion erosion's erotic erotically eroticism eroticism's err errand errand's errands errant errants erratic erratically erratics erred erring erroneous erroneously error error's errors errs erstwhile erudite erudition erudition's erupt erupted erupting eruption eruption's eruptions erupts es escalate escalated escalates escalating escalation escalation's escalations escalator escalator's escalators escapade escapade's escapades escape escaped escapes escaping escapism escapism's escapist escapists eschew eschewed eschewing eschews escort escort's escorted escorting escorts esoteric especial especially espionage espionage's espouse espoused espouses espousing espresso espresso's espressos essay essay's essayed essaying essays essence essence's essences essential essentially essentials establish established establishes establishing establishment establishment's establishments estate estate's estates esteem esteemed esteeming esteems esthetic esthetically estimable estimate estimated estimates estimating estimation estimation's estimations estrange estranged estrangement estrangement's estrangements estranges estranging estuaries estuary estuary's etch etched etches etching etching's etchings eternal eternally eternities eternity eternity's ether ether's ethereal ethic ethic's ethical ethically ethicals ethics ethnic ethnics ethos ethos's etiquette etiquette's etymological etymologies etymology etymology's eulogies eulogise eulogised eulogises eulogising eulogy eulogy's eunuch eunuch's eunuchs euphemism euphemism's euphemisms euphemistic euphemistically euphoria euphoria's euphoric eureka euthanasia euthanasia's evacuate evacuated evacuates evacuating evacuation evacuation's evacuations evacuee evacuee's evacuees evade evaded evades evading evaluate evaluated evaluates evaluating evaluation evaluation's evaluations evangelical evangelicals evangelism evangelism's evangelist evangelist's evangelistic evangelists evaporate evaporated evaporates evaporating evaporation evaporation's evasion evasion's evasions evasive eve eve's even evened evener evenest evenhanded evening evening's evenings evenly evenness evenness's evens event event's eventful events eventual eventualities eventuality eventuality's eventually ever evergreen evergreens everlasting everlastings evermore every everybody everyday everyone everyplace everything everywhere eves evict evicted evicting eviction eviction's evictions evicts evidence evidence's evidenced evidences evidencing evident evidently evidents evil eviller evillest evils evocative evoke evoked evokes evoking evolution evolution's evolutionary evolve evolved evolves evolving ewe ewe's ewes ex exacerbate exacerbated exacerbates exacerbating exact exacted exacter exactest exacting exactly exacts exaggerate exaggerated exaggerates exaggerating exaggeration exaggeration's exaggerations exalt exaltation exaltation's exalted exalting exalts exam exam's examination examination's examinations examine examined examiner examiner's examiners examines examining example example's exampled examples exampling exams exasperate exasperated exasperates exasperating exasperation exasperation's excavate excavated excavates excavating excavation excavation's excavations exceed exceeded exceeding exceedingly exceeds excel excelled excellence excellence's excellent excellently excelling excels except excepted excepting exception exception's exceptional exceptionally exceptions excepts excerpt excerpt's excerpted excerpting excerpts excess excess's excesses excessive excessively exchange exchanged exchanges exchanging excise excise's excised excises excising excision excision's excisions excitable excite excited excitedly excitement excitement's excitements excites exciting exclaim exclaimed exclaiming exclaims exclamation exclamation's exclamations exclude excluded excludes excluding exclusion exclusion's exclusive exclusively exclusives excommunicate excommunicated excommunicates excommunicating excommunication excommunication's excommunications excrement excrement's excrete excreted excretes excreting excruciating excruciatingly excursion excursion's excursions excusable excuse excused excuses excusing exec exec's execs executable execute executed executes executing execution execution's executioner executioner's executioners executions executive executive's executives executor executor's executors exemplary exemplified exemplifies exemplify exemplifying exempt exempted exempting exemption exemption's exemptions exempts exercise exercised exercises exercising exert exerted exerting exertion exertion's exertions exerts exes exhale exhaled exhales exhaling exhaust exhausted exhausting exhaustion exhaustion's exhaustive exhaustively exhausts exhibit exhibited exhibiting exhibition exhibition's exhibitionism exhibitionism's exhibitionist exhibitionist's exhibitionists exhibitions exhibitor exhibitor's exhibitors exhibits exhilarate exhilarated exhilarates exhilarating exhilaration exhilaration's exhort exhortation exhortation's exhortations exhorted exhorting exhorts exhumation exhumation's exhumations exhume exhumed exhumes exhuming exile exile's exiled exiles exiling exist existed existence existence's existences existent existential existentially existing exists exit exit's exited exiting exits exodus exodus's exoduses exonerate exonerated exonerates exonerating exoneration exoneration's exorbitant exorcism exorcism's exorcisms exorcist exorcist's exorcists exotic exotics expand expandable expanded expanding expands expanse expanse's expanses expansion expansion's expansionist expansionist's expansionists expansions expansive expatriate expatriated expatriates expatriating expect expectancy expectancy's expectant expectantly expectation expectation's expectations expected expecting expects expediencies expediency expediency's expedient expedients expedite expedited expedites expediting expedition expedition's expeditions expel expelled expelling expels expend expendable expendables expended expending expenditure expenditure's expenditures expends expense expense's expenses expensive expensively experience experience's experienced experiences experiencing experiment experiment's experimental experimentally experimentation experimentation's experimented experimenting experiments expert expert's expertise expertise's expertly experts expiration expiration's expire expired expires expiring expiry expiry's explain explained explaining explains explanation explanation's explanations explanatory expletive expletive's expletives explicable explicit explicitly explicits explode exploded explodes exploding exploit exploit's exploitation exploitation's exploited exploiting exploits exploration exploration's explorations exploratory explore explored explorer explorer's explorers explores exploring explosion explosion's explosions explosive explosives expo expo's exponent exponent's exponential exponentially exponents export export's exportation exportation's exported exporter exporter's exporters exporting exports expos expose exposed exposes exposing exposition exposition's expositions exposure exposure's exposures expound expounded expounding expounds express expressed expresses expressing expression expression's expressions expressive expressively expressly expressway expressway's expressways expropriate expropriated expropriates expropriating expropriation expropriation's expropriations expulsion expulsion's expulsions exquisite exquisitely extant extemporaneous extend extended extending extends extension extension's extensions extensive extensively extent extent's extents exterior exterior's exteriors exterminate exterminated exterminates exterminating extermination extermination's exterminations exterminator exterminator's exterminators external externally externals extinct extincted extincting extinction extinction's extinctions extincts extinguish extinguished extinguisher extinguisher's extinguishers extinguishes extinguishing extol extoll extolled extolling extolls extols extort extorted extorting extortion extortion's extortionate extorts extra extract extracted extracting extraction extraction's extractions extracts extracurricular extracurriculars extradite extradited extradites extraditing extradition extradition's extraditions extraneous extraordinaries extraordinarily extraordinary extrapolate extrapolated extrapolates extrapolating extrapolation extrapolation's extrapolations extras extraterrestrial extraterrestrials extravagance extravagance's extravagances extravagant extravagantly extreme extremely extremer extremes extremest extremism extremism's extremist extremist's extremists extremities extremity extremity's extricate extricated extricates extricating extrovert extrovert's extroverted extroverts exuberance exuberance's exuberant exude exuded exudes exuding exult exultant exultation exultation's exulted exulting exults eye eye's eyeball eyeball's eyeballed eyeballing eyeballs eyebrow eyebrow's eyebrows eyed eyeglass eyeglasses eyeing eyelash eyelash's eyelashes eyelid eyelid's eyelids eyeliner eyeliner's eyeliners eyes eyesight eyesight's eyesore eyesore's eyesores eyewitness eyewitness's eyewitnesses eying f fable fable's fables fabric fabric's fabricate fabricated fabricates fabricating fabrication fabrication's fabrications fabrics fabulous facade facade's facades face face's faced faceless faces facet facet's faceted faceting facetious facetiously facets facetted facetting facial facials facile facilitate facilitated facilitates facilitating facilities facility facility's facing facing's facsimile facsimile's facsimiled facsimileing facsimiles fact fact's faction faction's factions factor factor's factored factorial factorial's factories factoring factorisation factors factory factory's facts factual factually faculties faculty faculty's fad fad's fade faded fades fading fading's fads fag fag's fagged fagging faggot faggot's faggoted faggoting faggots fags fail failed failing failing's failings fails failure failure's failures faint fainted fainter faintest fainting faintly faints fair fairer fairest fairground fairground's fairgrounds fairies fairly fairness fairness's fairs fairy fairy's faith faith's faithed faithful faithfully faithfulness faithfulness's faithfuls faithing faithless faiths fake faked fakes faking falcon falcon's falconry falconry's falcons fall fall's fallacies fallacious fallacy fallacy's fallen fallible falling fallout fallout's falls false falsehood falsehood's falsehoods falsely falser falsest falsetto falsetto's falsettos falsification falsification's falsifications falsified falsifies falsify falsifying falsities falsity falsity's falter faltered faltering falterings falters fame fame's famed familiar familiarise familiarised familiarises familiarising familiarity familiarity's familiarly familiars families family family's famine famine's famines famish famished famishes famishing famous famously fan fan's fanatic fanatic's fanatical fanatically fanaticism fanaticism's fanatics fancied fancier fancies fanciest fanciful fancy fancying fanfare fanfare's fanfares fang fang's fangs fanned fannies fanning fanny fanny's fans fantasied fantasies fantasise fantasised fantasises fantasising fantastic fantastically fantasy fantasy's fantasying far faraway farce farce's farces farcical fare fare's fared fares farewell farewell's farewells faring farm farm's farmed farmer farmer's farmers farmhouse farmhouse's farmhouses farming farming's farmland farmland's farms farmyard farmyard's farmyards farsighted fart fart's farted farther farthest farting farts fascinate fascinated fascinates fascinating fascination fascination's fascinations fascism fascism's fascist fascist's fascists fashion fashion's fashionable fashionably fashioned fashioning fashions fast fasted fasten fastened fastener fastener's fasteners fastening fastening's fastenings fastens faster fastest fastidious fasting fasts fat fat's fatal fatalism fatalism's fatalistic fatalities fatality fatality's fatally fate fate's fated fateful fates father father's fathered fatherhood fatherhood's fathering fatherland fatherland's fatherlands fatherly fathers fathom fathom's fathomed fathoming fathoms fatigue fatigue's fatigued fatigues fatiguing fating fats fatten fattened fattening fattenings fattens fatter fattest fattier fatties fattiest fatty fatuous faucet faucet's faucets fault fault's faulted faultier faultiest faulting faultless faults faulty fauna fauna's faunae faunas favour favour's favourable favourably favoured favouring favourite favourite's favourites favouritism favouritism's favours fawn fawn's fawned fawning fawns fax faxed faxes faxing faze fazed fazes fazing fear fear's feared fearful fearfuller fearfullest fearfully fearing fearless fearlessly fearlessness fearlessness's fears fearsome feasibility feasibility's feasible feast feast's feasted feasting feasts feat feat's feather feather's feathered featherier featheriest feathering feathers feathery feats feature feature's featured features featuring fecal feces fed federal federalism federalism's federalist federalist's federalists federals federate federated federates federating federation federation's federations feds fee fee's feeble feebler feeblest feed feedback feedback's feedbag feedbag's feedbags feeder feeder's feeders feeding feeding's feedings feeds feel feeler feeler's feelers feeling feeling's feelings feels fees feet feet's feign feigned feigning feigns feint feint's feinted feinting feints feistier feistiest feisty feline felines fell felled feller fellest felling fellow fellow's fellows fellowship fellowship's fellowships fells felon felon's felonies felons felony felony's felt felted felting felts female females feminine feminines femininity femininity's feminism feminism's feminist feminist's feminists fems fen fen's fence fence's fenced fences fencing fencing's fend fended fender fender's fenders fending fends fer ferment ferment's fermentation fermentation's fermented fermenting ferments fern fern's ferns ferocious ferociously ferocity ferocity's ferret ferret's ferreted ferreting ferrets ferried ferries ferry ferry's ferrying fertile fertilisation fertilisation's fertilise fertilised fertiliser fertiliser's fertilisers fertilises fertilising fertility fertility's fervent fervently fervour fervour's fest fester festered festering festers festival festival's festivals festive festivities festivity festivity's festoon festoon's festooned festooning festoons fests fetch fetched fetches fetching feted fetid feting fetish fetish's fetishes fetter fetter's fettered fettering fetters feud feud's feudal feudalism feudalism's feuded feuding feuds fever fever's feverish feverishly fevers few fewer fewest fez fez's fezes fezzes fianc fianc's fiance fiances fiancs fiasco fiasco's fiascoes fiascos fiat fiat's fiats fib fib's fibbed fibber fibber's fibbers fibbing fibre fibre's fibreglass fibreglass's fibres fibrous fibs fices fiche fiche's fickle fickler ficklest ficoes fiction fiction's fictional fictions fictitious fiddle fiddle's fiddled fiddler fiddler's fiddlers fiddles fiddling fiddly fidelity fidelity's fidget fidgeted fidgeting fidgets fidgety field field's fielded fielding fields fieldwork fieldwork's fiend fiend's fiendish fiendishly fiends fierce fiercely fierceness fierceness's fiercer fiercest fierier fieriest fiery fiesta fiesta's fiestas fifteen fifteen's fifteens fifteenth fifteenths fifth fifths fifties fiftieth fiftieths fifty fifty's fig fig's figged figging fight fighter fighter's fighters fighting fights figment figment's figments figs figurative figuratively figure figure's figured figurehead figurehead's figureheads figures figuring filament filament's filaments filch filched filches filching file file's filed files filibuster filibuster's filibustered filibustering filibusters filigree filigree's filigreed filigreeing filigrees filing fill filled filler filler's fillet fillet's filleted filleting fillets fillies filling filling's fills filly filly's film film's filmed filmier filmiest filming filming's filmmaker filmmakers films filmy filter filter's filtered filtering filters filth filth's filthier filthiest filthy fin fin's finagle finagled finagles finagling final finale finale's finales finalise finalised finalises finalising finalist finalist's finalists finality finality's finally finals finance finance's financed finances financial financially financier financier's financiers financing finch finch's finches find finder finder's finders finding finding's findings finds fine fine's fined finely finer fines finesse finesse's finessed finesses finessing finest finger finger's fingered fingering fingernail fingernail's fingernails fingerprint fingerprint's fingerprinted fingerprinting fingerprints fingers fingertip fingertip's fingertips finickier finickiest finicky fining finish finished finishes finishing finite finner fins fir fir's fire fire's firearm firearm's firearms firebrand firebrand's firebrands firecracker firecracker's firecrackers fired firefighter firefighters fireflies firefly firefly's fireman fireman's firemen fireplace fireplace's fireplaces fireproof fireproofed fireproofing fireproofs fires fireside fireside's firesides firewall firewalled firewalling firewalls firewood firewood's firework firework's fireworks firing firing's firm firmed firmer firmest firming firmly firmness firmness's firms firmware firmware's firring firs first firsthand firstly firsts fiscal fiscals fish fish's fishbowl fishbowl's fishbowls fished fisher fisher's fisheries fisherman fisherman's fishermen fishery fishery's fishes fishier fishiest fishing fishing's fishnet fishnet's fishnets fishtail fishtail's fishtailed fishtailing fishtails fishy fission fission's fissure fissure's fissures fist fist's fists fit fit's fitful fitness fitness's fits fitted fitter fittest fitting fittings five five's fiver fiver's fives fix fixable fixation fixation's fixations fixed fixes fixing fixing's fixture fixture's fixtures fizz fizzed fizzes fizzier fizziest fizzing fizzle fizzled fizzles fizzling fizzy fjord fjord's fjords flab flab's flabbergast flabbergasted flabbergasting flabbergasts flabbier flabbiest flabby flaccid flag flag's flagged flagging flagging's flagpole flagpole's flagpoles flagrant flagrantly flags flagship flagship's flagships flagstone flagstone's flagstones flail flail's flailed flailing flails flair flair's flairs flak flak's flake flake's flaked flakes flakier flakiest flaking flaks flaky flamboyance flamboyance's flamboyant flamboyantly flame flame's flamed flamenco flamenco's flamencos flames flaming flamingo flamingo's flamingoes flamingos flamings flammable flammables flank flank's flanked flanking flanks flannel flannel's flannelled flannelling flannels flap flapjack flapjack's flapjacks flapped flapping flaps flare flared flares flaring flash flash's flashback flashback's flashbacks flashed flasher flasher's flashers flashes flashest flashier flashiest flashing flashing's flashlight flashlight's flashlights flashy flask flask's flasks flat flat's flatly flatness flatness's flats flatted flatten flattened flattening flattens flatter flattered flatterer flatterer's flatterers flattering flatters flattery flattery's flattest flatting flatulence flatulence's flaunt flaunted flaunting flaunts flavour flavour's flavoured flavouring flavouring's flavourings flavours flaw flaw's flawed flawing flawless flawlessly flaws flea flea's fleas fleck fleck's flecked flecking flecks fled fledged fledgling fledgling's fledglings flee fleece fleece's fleeced fleeces fleecier fleeciest fleecing fleecy fleeing flees fleet fleet's fleeted fleeter fleetest fleeting fleets flesh flesh's fleshed fleshes fleshier fleshiest fleshing fleshy flew flex flex's flexed flexes flexibility flexibility's flexible flexibly flexing flextime flick flicked flicker flickered flickering flickers flicking flicks flied flier flier's fliers flies fliest flight flight's flightier flightiest flightless flights flighty flimsier flimsiest flimsiness flimsiness's flimsy flinch flinched flinches flinching fling flinging flings flint flint's flints flip flippant flipped flipper flipper's flippers flippest flipping flips flirt flirtation flirtation's flirtations flirtatious flirted flirting flirts flit flits flitted flitting float floated floating floats flock flock's flocked flocking flocks flog flogged flogging flogging's floggings flogs flood flood's flooded flooder floodgate floodgate's floodgates flooding floodlight floodlight's floodlighted floodlighting floodlights floodlit floods floor floor's floored flooring flooring's floors floozie floozies floozy floozy's flop flophouse flophouse's flophouses flopped floppier floppies floppiest flopping floppy flops flora flora's florae floral floras florid florist florist's florists floss floss's flossed flosses flossing flotilla flotilla's flotillas flounce flounced flounces flouncing flounder floundered floundering flounders flour flour's floured flouring flourish flourished flourishes flourishing flours flout flouted flouting flouts flow flowed flower flower's flowerbed flowerbed's flowerbeds flowered flowerier floweriest flowering flowerpot flowerpot's flowerpots flowers flowery flowing flown flows flu flu's flub flubbed flubbing flubs fluctuate fluctuated fluctuates fluctuating fluctuation fluctuation's fluctuations flue flue's fluency fluency's fluent fluently fluents flues fluff fluff's fluffed fluffier fluffiest fluffing fluffs fluffy fluid fluid's fluidity fluidity's fluids fluke fluke's fluked flukes fluking flung flunk flunked flunkies flunking flunks flunky flunky's fluorescent fluoride fluoride's fluorides flurried flurries flurry flurry's flurrying flush flushed flusher flushes flushest flushing fluster flustered flustering flusters flute flute's fluted flutes fluting flutist flutist's flutists flutter fluttered fluttering flutters flux flux's fluxed fluxes fluxing fly flyer flyer's flyers flying flyover flyover's flyovers flyswatter flyswatters foal foal's foaled foaling foals foam foam's foamed foamier foamiest foaming foams foamy focal foci foci's focus focus's focused focuses focusing focussed focusses focussing fodder fodder's fodders foe foe's foes foetal foetus foetus's foetuses fog fog's fogbound fogey fogey's fogeys fogged foggier foggiest fogging foggy foghorn foghorn's foghorns fogs foible foible's foibles foil foiled foiling foils foist foisted foisting foists fold folded folder folder's folders folding folds foliage foliage's folk folk's folklore folklore's folks folksier folksiest folksy follicle follicle's follicles follies follow followed follower follower's followers following followings follows folly folly's foment fomented fomenting foments fond fond's fonded fonder fondest fonding fondle fondled fondles fondling fondly fondness fondness's fonds font font's fonts food food's foods foodstuff foodstuff's foodstuffs fool fool's fooled foolhardier foolhardiest foolhardy fooling foolish foolisher foolishest foolishly foolishness foolishness's foolproof fools foot foot's footage footage's football football's footballs footbridge footbridge's footbridges footed foothill foothill's foothills foothold foothold's footholds footing footing's footings footlights footlocker footlocker's footlockers footloose footnote footnote's footnoted footnotes footnoting footpath footpath's footpaths footprint footprint's footprints foots footsie footsie's footsies footstep footstep's footsteps footstool footstool's footstools footwear footwear's footwork footwork's for fora forage forage's foraged forages foraging foray foray's forayed foraying forays forbad forbade forbear forbearance forbearance's forbearing forbears forbid forbidden forbidding forbiddings forbids forbore forborne force force's forced forceful forcefully forceps forceps's forces forcible forcibly forcing ford ford's forded fording fords fore forearm forearm's forearmed forearming forearms forebode foreboded forebodes foreboding foreboding's forebodings forecast forecasted forecasting forecasts foreclose foreclosed forecloses foreclosing foreclosure foreclosure's foreclosures forefather forefather's forefathers forefinger forefinger's forefingers forefront forefront's forefronts forego foregoes foregoing foregoings foregone foreground foreground's foregrounded foregrounding foregrounds forehand forehands forehead forehead's foreheads foreign foreigner foreigner's foreigners foreleg foreleg's forelegs foreman foreman's foremen foremost forensic forensics foreplay foreplay's forerunner forerunner's forerunners fores foresaw foresee foreseeable foreseeing foreseen foresees foreshadow foreshadowed foreshadowing foreshadows foresight foresight's foreskin foreskin's foreskins forest forest's forestall forestalled forestalling forestalls forested foresting forestry forestry's forests foretaste foretaste's foretasted foretastes foretasting foretell foretelling foretells forethought forethought's foretold forever forewarn forewarned forewarning forewarns forewent foreword foreword's forewords forfeit forfeit's forfeited forfeiting forfeits forgave forge forge's forged forger forger's forgeries forgers forgery forgery's forges forget forgetful forgetfulness forgetfulness's forgets forgetting forging forgivable forgive forgiven forgiveness forgiveness's forgives forgiving forgo forgoes forgoing forgone forgot forgotten fork fork's forked forking forklift forklift's forklifts forks forlorn forlorner forlornest form form's formal formaldehyde formaldehyde's formalise formalised formalises formalising formalities formality formality's formally formals format format's formation formation's formations formative formats formatted formatting formed former formerly formidable formidably forming formless forms formula formula's formulae formulate formulated formulates formulating formulation formulation's formulations fornicate fornicated fornicates fornicating fornication fornication's forsake forsaken forsakes forsaking forsook forswear forswearing forswears forswore forsworn fort fort's forte forte's fortes forth forthcoming forthright forthwith forties fortieth fortieths fortification fortification's fortifications fortified fortifies fortify fortifying fortitude fortitude's fortnight fortnight's fortnightly fortress fortress's fortressed fortresses fortressing forts fortuitous fortunate fortunately fortune fortune's fortunes forty forty's forum forum's forums forward forwarded forwarder forwardest forwarding forwarding's forwards forwent fossil fossil's fossilise fossilised fossilises fossilising fossils foster fostered fostering fosters fought foul fouled fouler foulest fouling fouls found foundation foundation's foundations founded founder founder's foundered foundering founders founding foundling foundling's foundries foundry foundry's founds fount fount's fountain fountain's fountained fountaining fountains founts four four's fours fourteen fourteen's fourteens fourteenth fourteenths fourth fourthly fourths fowl fowl's fowled fowling fowls fox fox's foxed foxes foxhole foxhole's foxholes foxier foxiest foxing foxtrot foxtrot's foxtrots foxtrotted foxtrotting foxy foyer foyer's foyers fracas fracas's fracases fractal fraction fraction's fractional fractionally fractions fractious fracture fracture's fractured fractures fracturing fragile fragility fragility's fragment fragment's fragmentary fragmentation fragmentation's fragmented fragmenting fragments fragrance fragrance's fragrances fragrant frail frailer frailest frailties frailty frailty's frame frame's framed frames framework framework's frameworks framing franc franc's franchise franchise's franchised franchises franchising francs frank franked franker frankest frankfurter frankfurter's frankfurters franking frankly frankness frankness's franks frantic frantically frat frat's fraternal fraternise fraternised fraternises fraternising fraternities fraternity fraternity's frats fraud fraud's frauds fraudulent fraudulently fraught fraughted fraughting fraughts fray fray's frayed fraying frays freak freak's freaked freaking freaks freckle freckle's freckled freckles freckling free freebie freebie's freebies freed freedom freedom's freedoms freehand freeing freelance freelance's freelanced freelancer freelancers freelances freelancing freeload freeloaded freeloader freeloader's freeloaders freeloading freeloads freely freer frees freest freethinker freethinker's freethinkers freethinking freeway freeway's freeways freewheel freewheeled freewheeling freewheels freeze freezer freezer's freezers freezes freezing freight freight's freighted freighter freighter's freighters freighting freights french frenetic frenzied frenzies frenzy frenzy's frequencies frequency frequency's frequent frequented frequenter frequentest frequenting frequently frequents fresh freshen freshened freshening freshens fresher fresher's freshest freshly freshman freshman's freshmen freshness freshness's freshwater freshwater's fret fretful fretfully frets fretted fretting friar friar's friars friction friction's fridge fridge's fridges fried friend friend's friendless friendlier friendlies friendliest friendliness friendliness's friendly friends friendship friendship's friendships fries fries's frieze frieze's friezed friezes friezing frigate frigate's frigates fright fright's frighted frighten frightened frightening frighteningly frightens frightful frightfully frighting frights frigid frigidity frigidity's frill frill's frillier frillies frilliest frills frilly fringe fringe's fringed fringes fringing frisk frisked friskier friskiest frisking frisks frisky fritter frittered frittering fritters frivolities frivolity frivolity's frivolous frivolously friz frizz frizzed frizzes frizzier frizziest frizzing frizzy fro frock frock's frocks frog frog's frogs frolic frolic's frolicked frolicking frolics from frond frond's fronds front front's frontage frontage's frontages frontal fronted frontier frontier's frontiers fronting fronts frost frost's frostbit frostbite frostbite's frostbites frostbiting frostbitten frosted frostier frostiest frosting frosting's frosts frosty froth froth's frothed frothier frothiest frothing froths frothy frown frowned frowning frowns froze frozen frugal frugality frugality's frugally fruit fruit's fruitcake fruitcake's fruitcakes fruited fruitful fruitfuller fruitfullest fruitier fruitiest fruiting fruition fruition's fruitless fruitlessly fruits fruity frumpier frumpiest frumpy frustrate frustrated frustrates frustrating frustration frustration's frustrations fry frying fuck fucked fucker fucker's fuckers fucking fucks fudge fudge's fudged fudges fudging fuel fuel's fuelled fuelling fuels fugitive fugitive's fugitives fulcra fulcrum fulcrum's fulcrums fulfil fulfilled fulfilling fulfilment fulfilment's fulfils full fulled fuller fuller's fullest fulling fullness fullness's fulls fully fumble fumbled fumbles fumbling fume fumed fumes fumigate fumigated fumigates fumigating fumigation fumigation's fuming fun fun's function function's functional functionality functionally functioned functioning functions fund fund's fundamental fundamentalism fundamentalism's fundamentalist fundamentalist's fundamentalists fundamentally fundamentals funded funding funds funeral funeral's funerals fungal fungals fungi fungi's fungicide fungicide's fungicides fungus fungus's funguses funk funk's funked funkier funkiest funking funks funky funnel funnel's funnelled funnelling funnels funner funnest funnier funnies funniest funnily funny fur fur's furies furious furiously furl furled furling furlong furlong's furlongs furlough furlough's furloughed furloughing furloughs furls furnace furnace's furnaces furnish furnished furnishes furnishing furnishings furniture furniture's furor furor's furors furred furrier furriest furring furrow furrow's furrowed furrowing furrows furry furs further furthered furthering furthermore furthers furthest furtive furtively furtiveness furtiveness's fury fury's fuse fuse's fused fuselage fuselage's fuselages fuses fusing fusion fusion's fuss fuss's fussed fusses fussier fussiest fussing fussy futile futilely futility futility's future future's futures futuristic futuristics fuzz fuzz's fuzzed fuzzes fuzzier fuzziest fuzzing fuzzy fte fte's ftes g gab gabbed gabbier gabbiest gabbing gabby gable gable's gabled gables gabling gabs gadget gadget's gadgets gaff gaffe gaffe's gaffed gaffes gaffing gaffs gag gage gaged gages gagged gagging gaggle gaggles gaging gags gaiety gaiety's gaily gain gained gainful gaining gains gait gait's gaits gal gal's gala gala's galactic galas galaxies galaxy galaxy's gale gale's gales gall gall's gallant gallantly gallantry gallantry's gallants gallbladder gallbladder's gallbladders galled galleried galleries gallery gallery's gallerying galley galley's galleys galling gallivant gallivanted gallivanting gallivants gallon gallon's gallons gallop galloped galloping gallops gallows gallows's gallowses galls galore galores galosh galoshe galoshes gals galvanise galvanised galvanises galvanising gambit gambit's gambits gamble gambled gambler gambler's gamblers gambles gambling game game's gamed gamer games gamest gaming gaming's gamma gamma's gamut gamut's gamuts gander gander's ganders gang gang's ganged ganging gangland gangland's gangling gangplank gangplank's gangplanks gangrene gangrene's gangrened gangrenes gangrening gangs gangster gangster's gangsters gangway gangway's gangways gaol gaol's gap gap's gape gaped gapes gaping gapings gaps garage garage's garaged garages garaging garb garb's garbage garbage's garbed garbing garble garbled garbles garbling garbs garden garden's gardened gardener gardener's gardeners gardenia gardenia's gardenias gardening gardening's gardens gargantuan gargle gargled gargles gargling gargoyle gargoyle's gargoyles garish garland garland's garlanded garlanding garlands garlic garlic's garlicked garlicking garlics garment garment's garments garnet garnet's garnets garnish garnished garnishes garnishing garret garret's garrets garrison garrison's garrisoned garrisoning garrisons garrulous garter garter's garters gas gas's gaseous gases gash gashed gashes gashing gasket gasket's gaskets gasoline gasoline's gasp gasped gasping gasps gassed gasses gassier gassiest gassing gassy gastric gastronomic gasworks gasworks's gate gate's gatecrasher gatecrashers gated gates gateway gateway's gateways gather gathered gathering gathering's gatherings gathers gating gauche gaucher gauchest gaudier gaudiest gaudy gauge gauge's gauged gauges gauging gaunt gaunted gaunter gauntest gaunting gauntlet gauntlet's gauntlets gaunts gauze gauze's gave gavel gavel's gavels gawk gawk's gawked gawkier gawkies gawkiest gawking gawks gawky gay gayer gayest gays gaze gazebo gazebo's gazeboes gazebos gazed gazelle gazelle's gazelles gazes gazette gazette's gazetted gazettes gazetting gazing gear gear's geared gearing gearing's gears gearshift gearshift's gearshifts gee geed geeing geek geek's geekier geekiest geeks geeky gees geese geese's geezer geezer's geezers geisha geisha's geishas gel gel's gelatin gelatin's geld gelded gelding gelding's geldings gelds gelled gelling gels gelt gem gem's gems gender gender's genders gene gene's genealogical genealogies genealogist genealogist's genealogists genealogy genealogy's genera genera's general generalisation generalisation's generalisations generalise generalised generalises generalising generality generality's generally generals generate generated generates generating generation generation's generations generator generator's generators generic generically generics generosities generosity generosity's generous generously genes geneses genesis genesis's genetic genetically geneticist geneticist's geneticists genetics genetics's genial genially genie genie's genies genii genital genitalia genitals genius genius's geniuses genocide genocide's genre genre's genres gent gent's genteel genteeler genteelest gentile gentiles gentility gentility's gentle gentled gentleman gentleman's gentlemen gentleness gentleness's gentler gentles gentlest gentling gently gentries gentrification gentrification's gentry gentry's gents genuflect genuflected genuflecting genuflects genuine genuinely genuineness genuineness's genus genuses geographer geographer's geographers geographic geographical geographically geographies geography geography's geologic geological geologies geologist geologists geology geology's geometric geometrically geometries geometry geometry's geranium geranium's geraniums gerbil gerbil's gerbils geriatric geriatrics geriatrics's germ germ's germicide germicide's germicides germinate germinated germinates germinating germination germination's germs gerrymander gerrymandered gerrymandering gerrymanders gerund gerund's gerunds gestation gestation's gesticulate gesticulated gesticulates gesticulating gesture gesture's gestured gestures gesturing get getaway getaway's getaways gets getting getup getup's geyser geyser's geysers ghastlier ghastliest ghastly ghetto ghetto's ghettoes ghettos ghost ghost's ghosted ghosting ghostlier ghostliest ghostly ghosts ghostwriter ghostwriters ghoul ghoul's ghoulish ghouls giant giant's giants gibber gibbered gibbering gibberish gibberish's gibbers gibe gibed gibes gibing giblet giblets giddier giddiest giddiness giddiness's giddy gift gift's gifted gifting gifts gig gig's gigabyte gigabytes gigantic gigged gigging giggle giggled giggles giggling gigs gild gilded gilding gilds gill gill's gills gilt gilts gimme gimmick gimmick's gimmicks gimmicky gin gin's ginger ginger's gingerbread gingerbread's gingerly gingham gingham's ginned ginning gins giraffe giraffe's giraffes girder girder's girders girdle girdle's girdled girdles girdling girl girl's girlfriend girlfriend's girlfriends girlhood girlhood's girlhoods girlish girls girth girth's girths gist gist's give giveaway giveaway's giveaways given givens gives giving gizmo gizmo's gizmos gizzard gizzard's gizzards glacial glacier glacier's glaciers glad gladden gladdened gladdening gladdens gladder gladdest glade glade's glades gladiator gladiator's gladiators gladlier gladliest gladly glads glamor glamorise glamorised glamorises glamorising glamorous glamorously glamors glamour glamour's glamoured glamouring glamours glance glanced glances glancing gland gland's glands glandular glare glared glares glaring glass glass's glassed glasses glassier glassiest glassing glassware glassware's glassy glaze glazed glazes glazing glazing's gleam gleam's gleamed gleaming gleamings gleams glean gleaned gleaning gleans glee glee's gleeful gleefully glen glen's glens glib glibber glibbest glibly glide glided glider glider's gliders glides gliding glimmer glimmered glimmering glimmers glimpse glimpse's glimpsed glimpses glimpsing glint glinted glinting glints glisten glistened glistening glistens glitch glitches glitter glittered glittering glitterings glitters glitz glitzier glitziest glitzy gloat gloated gloating gloats glob glob's global globally globe globe's globed globes globetrotter globetrotter's globetrotters globing globs globular globule globule's globules gloom gloom's gloomier gloomiest gloomily gloominess gloominess's gloomy gloried glories glorification glorification's glorified glorifies glorify glorifying glorious gloriously glory glory's glorying gloss gloss's glossaries glossary glossary's glossed glosses glossier glossies glossiest glossing glossy glove glove's gloved gloves gloving glow glow's glowed glower glowered glowering glowers glowing glowingly glows glowworm glowworm's glowworms glucose glucose's glue glue's glued glueing glues gluing glum glumly glummer glummest glums glut glut's gluts glutted glutting glutton glutton's gluttons gluttony gluttony's glycerin glycerin's glycerine gnarl gnarled gnarlier gnarliest gnarling gnarls gnarly gnash gnashed gnashes gnashing gnat gnat's gnats gnaw gnawed gnawing gnawing's gnawn gnaws gnome gnome's gnomes gnu gnu's gnus go go's goad goad's goaded goading goads goal goal's goaled goalie goalie's goalies goaling goalkeeper goalkeeper's goalkeepers goalpost goalposts goals goat goat's goatee goatee's goatees goats gob gob's gobbed gobbing gobble gobbled gobbledygook gobbles gobbling goblet goblet's goblets goblin goblin's goblins gobs god god's godchild godchild's godchildren goddamn goddamned goddess goddess's goddesses godfather godfather's godfathers godforsaken godless godlier godliest godlike godly godmother godmother's godmothers godparent godparent's godparents gods godsend godsend's godsends goes gofer gofer's gofers goggle goggles going going's goings gold gold's golden goldener goldenest golder goldest goldfish goldfish's goldfishes golds goldsmith goldsmith's goldsmiths golf golf's golfed golfer golfer's golfers golfing golfs gollies golly gondola gondola's gondolas gone goner goner's goners gong gong's gonged gonging gongs gonna gonorrhoea gonorrhoea's goo goo's good goodbye goodbye's goodie goodies goodness goodness's goodnight goods goodwill goodwill's goody gooey goof goof's goofed goofier goofiest goofing goofs goofy gooier gooiest goon goon's goons goose goose's goosed gooses goosing gopher gopher's gophers gore gore's gored gores gorge gorge's gorged gorgeous gorgeously gorges gorging gorier goriest gorilla gorilla's gorillas goring gory gos gosh goshes gosling gosling's gospel gospel's gospels gossamer gossamer's gossip gossip's gossipped gossipping gossips got gotta gotten gouge gouged gouges gouging goulash goulash's goulashes gourd gourd's gourds gourmet gourmet's gourmets gout gout's govern governed governess governess's governesses governing government government's governmental governments governor governor's governors governorship governorship's governs gown gown's gowned gowning gowns grab grabbed grabber grabbing grabs grace grace's graced graceful gracefuller gracefullest gracefully gracefulness gracefulness's graceless graces gracing gracious graciously graciousness graciousness's grad grad's gradation gradation's gradations grade grade's graded grader grader's graders grades gradient gradient's gradients grading grads gradual gradually graduate graduate's graduated graduates graduating graduation graduation's graduations graffiti graffito graft graft's grafted grafting grafts grain grain's grainier grainiest grains grainy gram gram's grammar grammar's grammars grammatical grammatically gramophone gramophone's grams grand grandchild grandchild's grandchildren granddad granddad's granddads granddaughter granddaughter's granddaughters grander grandest grandeur grandeur's grandfather grandfather's grandfathered grandfathering grandfathers grandiose grandly grandma grandma's grandmas grandmother grandmother's grandmothers grandpa grandpa's grandparent grandparent's grandparents grandpas grands grandson grandson's grandsons grandstand grandstand's grandstanded grandstanding grandstands granite granite's grannie grannies granny granny's granola grant granted granting grants granular granulate granulated granulates granulating granule granule's granules grape grape's graped grapefruit grapefruit's grapefruits grapes grapevine grapevine's grapevines graph graph's graphed graphic graphical graphically graphics graphics's graphing graphite graphite's graphs graping grapple grappled grapples grappling grasp grasped grasping grasps grass grass's grassed grasses grasshopper grasshopper's grasshoppers grassier grassiest grassing grassland grassland's grassy grate grated grateful gratefuller gratefullest gratefully grater grater's graters grates gratification gratification's gratifications gratified gratifies gratify gratifying grating grating's gratings gratis gratitude gratitude's gratuities gratuitous gratuitously gratuity gratuity's grave grave's graved gravel gravel's gravelled gravelling gravels gravely graven graver graves gravest gravestone gravestone's gravestones graveyard graveyard's graveyards gravies graving gravitate gravitated gravitates gravitating gravitation gravitation's gravitational gravity gravity's gravy gravy's grayish graze grazed grazes grazing grease grease's greased greases greasier greasiest greasing greasy great greater greatest greatly greatness greatness's greats greed greed's greedier greediest greedily greediness greediness's greedy green green's greenback greenback's greenbacks greened greener greenery greenery's greenest greenhorn greenhorn's greenhorns greenhouse greenhouse's greenhouses greening greenish greens greet greeted greeting greeting's greetings greets gregarious gremlin gremlin's gremlins grenade grenade's grenades grew grey greyed greyer greyest greyhound greyhound's greyhounds greying greys grid grid's gridded griddle griddle's griddles griding gridiron gridiron's gridirons gridlock gridlocked gridlocking gridlocks grids grief grief's griefs grievance grievance's grievances grieve grieved grieves grieving grievous grill grille grille's grilled grilles grilling grills grim grimace grimace's grimaced grimaces grimacing grime grime's grimed grimes grimier grimiest griming grimly grimmer grimmest grimy grin grind grinder grinder's grinders grinding grinds grindstone grindstone's grindstones gringo gringo's gringos grinned grinning grins grip grip's gripe griped gripes griping gripped gripping grips grislier grisliest grisly gristle gristle's grit grit's grits gritted grittier grittiest gritting gritty grizzled grizzlier grizzlies grizzliest grizzly groan groan's groaned groaning groans grocer grocer's groceries grocers grocery grocery's groggier groggiest groggy groin groin's groins groom groom's groomed grooming grooms groove groove's grooved grooves groovier grooviest grooving groovy grope groped gropes groping gross grossed grosser grosses grossest grossing grossly grotesque grotesques grotto grotto's grottoes grottos grouch grouched grouches grouchier grouchiest grouching grouchy ground ground's grounded groundhog groundhogs grounding groundings groundless groundlessly grounds groundswell groundswells groundwork groundwork's group group's grouped grouper groupers groupie groupie's groupies grouping grouping's groupings groups grouse grouse's groused grouses grousing grove grove's grovel grovelled grovelling grovels groves grow grower grower's growers growing growl growled growling growls grown grows growth growth's growths grub grubbed grubbier grubbiest grubbing grubby grubs grudge grudge's grudged grudges grudging grudgings gruel gruel's gruelled gruelling gruellings gruels gruesome gruesomer gruesomest gruff gruffed gruffer gruffest gruffing gruffly gruffs grumble grumbled grumbles grumbling grumpier grumpiest grumpy grunge grungier grungiest grungy grunt grunted grunting grunts gs guacamole guacamole's guarantee guarantee's guaranteed guaranteeing guarantees guarantied guaranties guarantor guarantor's guarantors guaranty guaranty's guarantying guard guarded guardedly guardian guardian's guardians guarding guardrail guardrail's guardrails guards gubernatorial guerilla guerrilla guerrilla's guerrillas guess guessable guessed guesses guessing guesstimate guesstimate's guesstimated guesstimates guesstimating guesswork guesswork's guest guest's guested guesting guests guff guff's guffaw guffaw's guffawed guffawing guffaws guidance guidance's guide guidebook guidebook's guidebooks guided guideline guideline's guidelines guides guiding guild guild's guilds guile guile's guiled guileless guiles guiling guillotine guillotine's guillotined guillotines guillotining guilt guilt's guiltier guiltiest guiltily guiltless guilty guinea guinea's guise guise's guises guitar guitar's guitarist guitarist's guitarists guitars gulch gulch's gulches gulf gulf's gulfs gull gull's gulled gullet gullet's gullets gullibility gullibility's gullible gullies gulling gulls gully gully's gulp gulped gulping gulps gum gum's gumbo gumbo's gumbos gumdrop gumdrop's gumdrops gummed gummier gummiest gumming gummy gumption gumption's gums gun gun's gunboat gunboat's gunboats gunfire gunfire's gunk gunk's gunman gunman's gunmen gunned gunner gunner's gunners gunning gunnysack gunnysack's gunnysacks gunpoint gunpoint's gunpowder gunpowder's gunrunner gunrunner's gunrunners gunrunning gunrunning's guns gunshot gunshot's gunshots guppies guppy guppy's gurgle gurgled gurgles gurgling guru guru's gurus gush gushed gusher gusher's gushers gushes gushier gushiest gushing gushy gust gust's gusted gustier gustiest gusting gusto gusto's gusts gusty gut gut's guts gutsier gutsiest gutsy gutted gutter gutter's guttered guttering gutters gutting guttural gutturals guy guy's guyed guying guys guzzle guzzled guzzler guzzler's guzzlers guzzles guzzling gybe gybed gybes gybing gym gym's gymnasia gymnasium gymnasium's gymnasiums gymnast gymnast's gymnastics gymnastics's gymnasts gyms gynaecological gynaecologist gynaecologist's gynaecologists gynaecology gynaecology's gyp gypped gypping gyps gypsies gypsy gyrate gyrated gyrates gyrating gyration gyration's gyrations gyroscope gyroscope's gyroscopes h h'm ha haberdasheries haberdashery haberdashery's habit habit's habitable habitat habitat's habitation habitation's habitations habitats habits habitual habitually habituals hack hacked hacker hacker's hackers hacking hackney hackneyed hackneying hackneys hacks hacksaw hacksaw's hacksawed hacksawing hacksaws had haddock haddock's haddocks haded hades hading hadn't haemoglobin haemophiliac haemophiliac's haemophiliacs hag hag's haggard hagged hagging haggle haggled haggles haggling hags hail hail's hailed hailing hails hailstone hailstone's hailstones hair hair's hairbrush hairbrush's hairbrushes haircut haircut's haircuts haircutting hairdo hairdo's hairdos hairdresser hairdresser's hairdressers haired hairier hairiest hairline hairline's hairlines hairnet hairnet's hairnets hairpiece hairpiece's hairpieces hairs hairsplitting hairsplitting's hairstyle hairstyle's hairstyles hairstylist hairstylists hairy hale haled haler hales halest half half's halfhearted halfheartedly halftime halftimes halfway halibut halibut's halibuts haling hall hall's hallelujah hallelujahs hallmark hallmark's hallmarked hallmarking hallmarks hallow hallowed hallowing hallows halls hallucinate hallucinated hallucinates hallucinating hallucination hallucination's hallucinations hallucinogenic hallucinogenics hallway hallway's hallways halo halo's haloed haloes haloing halon halos halt halt's halted halter halter's haltered haltering halters halting haltings halts halve halved halves halves's halving ham ham's hamburger hamburger's hamburgers hamlet hamlet's hamlets hammed hammer hammer's hammered hammering hammering's hammerings hammers hamming hammock hammock's hammocks hamper hampered hampering hampers hams hamster hamster's hamsters hamstring hamstring's hamstringing hamstrings hamstrung hand hand's handbag handbag's handbagged handbagging handbags handbook handbook's handbooks handcuff handcuffed handcuffing handcuffs handcuffs's handed handedness handedness's handful handful's handfuls handgun handgun's handguns handicap handicap's handicapped handicapping handicaps handicraft handicraft's handicrafts handier handiest handing handiwork handiwork's handkerchief handkerchief's handkerchiefs handkerchieves handle handle's handlebar handlebar's handlebars handled handler handler's handlers handles handling handling's handmade handout handout's handouts handpick handpicked handpicking handpicks handrail handrail's handrails hands handsful handshake handshake's handsome handsomely handsomer handsomest handstand handstand's handstands handwriting handwriting's handwritten handy handyman handyman's handymen hang hangar hangar's hangars hanged hanger hanger's hangers hanging hanging's hangings hangout hangout's hangouts hangover hangover's hangovers hangs hanker hankered hankering hankering's hankerings hankers hankie hankie's hankies hanky haphazard haphazardly hapless happen happened happening happening's happenings happens happier happiest happily happiness happiness's happy harangue harangued harangues haranguing harass harassed harasses harassing harassment harassment's harbour harbour's harboured harbouring harbours hard hardback hardback's hardball hardball's hardcover hardcover's hardcovers harden hardened hardening hardens harder hardest hardheaded hardhearted hardier hardiest hardline hardliner hardliners hardly hardship hardship's hardships hardware hardware's hardwood hardwood's hardwoods hardy hare hare's harebrained hared harelip harelip's harelips harem harem's harems hares haring hark harked harking harks harlot harlot's harlots harm harm's harmed harmful harmfully harming harmless harmlessly harmonic harmonica harmonica's harmonicas harmonies harmonious harmoniously harmonisation harmonisation's harmonise harmonised harmonises harmonising harmony harmony's harms harness harness's harnessed harnesses harnessing harp harp's harped harping harping's harpist harpist's harpists harpoon harpoon's harpooned harpooning harpoons harps harpsichord harpsichord's harpsichords harried harries harrow harrowed harrowing harrows harry harrying harsh harsher harshest harshly harshness harshness's hart hart's harts harvest harvest's harvested harvester harvester's harvesters harvesting harvests has hash hash's hashed hashes hashing hashish hashish's hasn't hassle hassle's hassled hassles hassling haste haste's hasted hasten hastened hastening hastens hastes hastier hastiest hastily hasting hasty hat hat's hatch hatchback hatchback's hatchbacks hatched hatches hatchet hatchet's hatchets hatching hate hated hateful hatefully hates hating hatred hatred's hatreds hats hatted hatting haughtier haughtiest haughtily haughtiness haughtiness's haughty haul hauled hauling hauls haunch haunches haunt haunted haunting haunts have haven haven's haven't havens haves having havoc havoc's hawk hawk's hawked hawking hawks hay hay's hayed haying hays haystack haystack's haystacks haywire haywire's hazard hazard's hazarded hazarding hazardous hazards haze haze's hazed hazel hazel's hazelnut hazelnut's hazelnuts hazels hazes hazier haziest hazing hazing's hazings hazy he he'd he'll he's head head's headache headache's headaches headband headband's headbands headed header header's headers headfirst headgear headgear's headhunter headhunter's headhunters headier headiest heading heading's headings headland headland's headlands headlight headlight's headlights headline headline's headlined headlines headlining headlong headmaster headmaster's headmasters headmistress headmistress's headmistresses headphone headphones headquarter headquarters headrest headrest's headrests headroom headroom's heads headstone headstone's headstones headstrong headway headway's headwind headwind's headwinds heady heal healed healer healer's healers healing heals health health's healthful healthier healthiest healthily healthy heap heap's heaped heaping heaps hear heard hearing hearing's hearings hears hearsay hearsay's hearse hearse's hearsed hearses hearsing heart heart's heartache heartache's heartaches heartbeat heartbeat's heartbeats heartbreak heartbreak's heartbreaking heartbreaks heartbroke heartbroken heartburn heartburn's hearted hearten heartened heartening heartens heartfelt hearth hearth's hearths heartier hearties heartiest heartily hearting heartland heartland's heartlands heartless hearts heartthrob heartthrob's heartthrobs heartwarming hearty heat heat's heated heatedly heater heater's heaters heath heath's heathen heathen's heathens heather heather's heating heats heave heaved heaven heaven's heavenlier heavenliest heavenly heavens heaves heavier heavies heaviest heavily heaviness heaviness's heaving heavy heavyweight heavyweight's heavyweights heck heckle heckled heckler heckler's hecklers heckles heckling hectic hectics hedge hedge's hedged hedgehog hedgehog's hedgehogs hedges hedging hedonism hedonism's hedonist hedonist's hedonistic hedonists heed heed's heeded heeding heedless heeds heel heel's heeled heeling heels heftier heftiest hefty heifer heifer's heifers height height's heighten heightened heightening heightens heights heinous heir heir's heiress heiress's heiresses heirloom heirloom's heirlooms heirs heist heist's heisted heisting heists held helicopter helicopter's helicoptered helicoptering helicopters heliport heliport's heliports helium helium's hell hell's helling hellish hello hello's helloed hellos hells helm helm's helmet helmet's helmeted helmeting helmets helms help helped helper helper's helpers helpful helpfully helpfulness helpfulness's helping helping's helpings helpless helplessly helplessness helplessness's helps hem hem's hemisphere hemisphere's hemispheres hemline hemline's hemlines hemlock hemlock's hemlocks hemmed hemming hemoglobin's hemophilia hemophilia's hemorrhage hemorrhage's hemorrhaged hemorrhages hemorrhaging hemorrhoid hemorrhoids hemp hemp's hems hen hen's hence henceforth hences henchman henchman's henchmen hens hepatitis hepatitis's her herald herald's heralded heralding heralds herb herb's herbal herbivore herbivore's herbivores herbivorous herbs herd herd's herded herding herds here hereabouts hereafter hereafters hereby hereditary heredity heredity's herein heresies heresy heresy's heretic heretic's heretical heretics herewith heritage heritage's heritages hermaphrodite hermaphrodite's hermetic hermetics hermit hermit's hermits hernia hernia's herniae hernias hero hero's heroes heroic heroically heroin heroin's heroine heroine's heroins heroism heroism's heron heron's herons heros herpes herpes's herring herring's herrings hers herself hertz hertz's hertzes hes hesitancy hesitancy's hesitant hesitantly hesitate hesitated hesitates hesitating hesitation hesitation's hesitations heterogeneous heterosexual heterosexual's heterosexuality heterosexuality's heterosexuals heuristic hew hewed hewing hewn hews hexadecimal hexagon hexagon's hexagonal hexagons hey heyday heyday's heydays hi hiatus hiatus's hiatuses hibernate hibernated hibernates hibernating hibernation hibernation's hiccough hiccough's hiccoughed hiccoughing hiccoughs hiccupped hiccupping hick hick's hickey hickey's hickeys hickories hickory hickory's hicks hid hidden hide hideaway hideaway's hideaways hided hideous hideously hideout hideout's hideouts hides hiding hiding's hierarchical hierarchies hierarchy hierarchy's hieroglyphic hieroglyphics hieroglyphics's high highbrow highbrow's highbrows higher highest highland highland's highlands highlight highlight's highlighted highlighter highlighters highlighting highlights highly highs highway highway's highways hijack hijacked hijacker hijacker's hijackers hijacking hijackings hijacks hike hiked hiker hiker's hikers hikes hiking hilarious hilariously hilarity hilarity's hill hill's hillbillies hillbilly hillbilly's hillier hilliest hills hillside hillside's hillsides hilltop hilltop's hilltops hilly hilt hilt's hilts him hims himself hind hinder hindered hindering hinders hindquarter hindquarters hindrance hindrance's hindrances hinds hindsight hindsight's hinge hinge's hinged hinges hinging hint hint's hinted hinterland hinterland's hinterlands hinting hints hip hip's hipped hipper hippest hippie hippie's hippier hippies hippiest hipping hippo hippo's hippopotami hippopotamus hippopotamus's hippopotamuses hippos hippy hips hire hired hires hiring his hiss hiss's hissed hisses hissing histogram histogram's historian historian's historians historic historical historically histories history history's histrionic histrionics histrionics's hit hitch hitched hitches hitchhike hitchhiked hitchhiker hitchhikers hitchhikes hitchhiking hitching hither hitherto hits hitting hive hive's hived hives hiving ho hoard hoard's hoarded hoarder hoarder's hoarders hoarding hoarding's hoards hoarse hoarsely hoarseness hoarseness's hoarser hoarsest hoax hoax's hoaxed hoaxes hoaxing hobbies hobbit hobble hobbled hobbles hobbling hobby hobby's hobbyhorse hobbyhorse's hobbyhorses hobgoblin hobgoblin's hobgoblins hobnob hobnobbed hobnobbing hobnobs hobo hobo's hoboed hoboes hoboing hobos hock hock's hocked hockey hockey's hocking hocks hodgepodge hodgepodge's hodgepodges hoe hoe's hoed hoeing hoes hog hog's hogged hogging hogs hoist hoisted hoisting hoists hokey hokier hokiest hold holder holder's holders holding holding's holdings holdover holdover's holdovers holds holdup holdup's holdups hole hole's holed holes holiday holiday's holidayed holidaying holidays holier holiest holiness holiness's holing holistic holler hollered hollering hollers hollies hollow hollowed hollower hollowest hollowing hollows holly holly's holocaust holocaust's holocausts hologram hologram's holograms holster holster's holstered holstering holsters holy homage homage's homaged homages homaging home home's homecoming homecoming's homecomings homed homeland homeland's homelands homeless homelessness homelessness's homelier homeliest homely homemade homemaker homemaker's homemakers homeowner homeowners homer homer's homered homering homeroom homeroom's homerooms homers homes homesick homesickness homesickness's homespun homestead homestead's homesteaded homesteading homesteads hometown hometown's hometowns homeward homewards homework homework's homey homeys homicidal homicide homicide's homicides homier homiest homing homoeopathic homoeopathy homoeopathy's homogeneity homogeneity's homogeneous homogenise homogenised homogenises homogenising homonym homonym's homonyms homophobic homosexual homosexual's homosexuality homosexuality's homosexuals homy honcho honchos hone hone's honed honer hones honest honester honestest honestly honesty honesty's honey honey's honeycomb honeycomb's honeycombed honeycombing honeycombs honeyed honeying honeymoon honeymoon's honeymooned honeymooning honeymoons honeys honeysuckle honeysuckle's honeysuckles honied honing honk honk's honked honking honks honoraries honorary honour honour's honourable honourably honoured honouring honours hood hood's hooded hooding hoodlum hoodlum's hoodlums hoods hoodwink hoodwinked hoodwinking hoodwinks hoof hoof's hoofed hoofing hoofs hook hook's hooked hooker hooker's hookers hookey hookey's hookier hookiest hooking hooks hooligan hooligan's hooligans hoop hoop's hooped hooping hoops hooray hoorayed hooraying hoorays hoot hoot's hooted hooter hooter's hooting hoots hooves hooves's hop hop's hope hope's hoped hopeful hopefully hopefulness hopefulness's hopefuls hopeless hopelessly hopelessness hopelessness's hopes hoping hopped hopper hopper's hopping hopping's hops hopscotch hopscotch's hopscotched hopscotches hopscotching horde horde's horded hordes hording horizon horizon's horizons horizontal horizontally horizontals hormone hormone's hormones horn horn's horned hornet hornet's hornets hornier horniest horns horny horoscope horoscope's horoscopes horrendous horrendously horrible horribles horribly horrid horrific horrified horrifies horrify horrifying horror horror's horrors horse horse's horseback horseback's horsed horseman horseman's horseplay horseplay's horsepower horsepower's horseradish horseradish's horseradishes horses horseshoe horseshoe's horseshoed horseshoeing horseshoes horsing horticultural horticulture horticulture's hose hose's hosed hoses hosiery hosiery's hosing hospice hospice's hospices hospitable hospital hospital's hospitalisation hospitalisation's hospitalisations hospitalise hospitalised hospitalises hospitalising hospitality hospitality's hospitals host host's hostage hostage's hostages hosted hostel hostel's hosteled hosteling hostelled hostelling hostels hostess hostess's hostessed hostesses hostessing hostile hostiles hostilities hostility hostility's hosting hosts hot hotbed hotbed's hotbeds hotcake hotcakes hotel hotel's hotels hothead hothead's hotheaded hotheads hotly hotshot hotshots hotter hottest hound hound's hounded hounding hounds hour hour's hourglass hourglass's hourglasses hourlies hourly hours house house's houseboat houseboat's houseboats housebound housebreak housebreaking housebreaks housebroke housebroken housed household household's households househusband househusbands housekeeper housekeeper's housekeepers housekeeping housekeeping's houses housewares housewarming housewarming's housewarmings housewife housewife's housewives housework housework's housing housing's housings hove hovel hovel's hovels hover hovered hovering hovers how howdied howdies howdy howdying however howl howl's howled howling howls hows hub hub's hubbub hubbub's hubbubs hubcap hubcap's hubcaps hubs huddle huddle's huddled huddles huddling hue hue's hued hues huff huff's huffed huffier huffiest huffing huffs huffy hug huge hugely huger hugest hugged hugger hugging hugs huh huhs hulk hulk's hulking hulks hull hull's hullabaloo hullabaloo's hullabaloos hulled hulling hulls hum human humane humanely humaner humanest humanise humanised humanises humanising humanism humanism's humanist humanist's humanists humanitarian humanitarianism humanitarianism's humanitarians humanities humanity humanity's humankind humankind's humanly humans humble humbled humbler humbles humblest humbling humblings humbly humbug humbug's humdrum humid humidified humidifies humidify humidifying humidity humidity's humiliate humiliated humiliates humiliating humiliation humiliation's humiliations humility humility's hummed humming hummingbird hummingbird's hummingbirds humorist humorist's humorists humorous humorously humour humour's humoured humouring humours hump hump's humped humping humps hums hunch hunch's hunchback hunchback's hunchbacks hunched hunches hunching hundred hundred's hundreds hundredth hundredths hung hunger hunger's hungered hungering hungers hungrier hungriest hungrily hungry hunk hunk's hunker hunkered hunkering hunkers hunks hunt hunted hunter hunter's hunters hunting hunting's hunts hurdle hurdle's hurdled hurdler hurdler's hurdlers hurdles hurdling hurl hurled hurling hurling's hurls hurrah hurrahed hurrahing hurrahs hurray hurrayed hurraying hurrays hurricane hurricane's hurricanes hurried hurriedly hurries hurry hurrying hurt hurtful hurting hurtle hurtled hurtles hurtling hurts husband husband's husbanded husbanding husbands hush hushed hushes hushing husk husk's husked huskier huskies huskiest huskily huskiness huskiness's husking husks husky hustle hustled hustler hustler's hustlers hustles hustling hut hut's hutch hutch's hutched hutches hutching huts hyacinth hyacinth's hyacinths hybrid hybrid's hybrids hydrant hydrant's hydrants hydraulic hydraulicked hydraulicking hydraulics hydraulics's hydroelectric hydrogen hydrogen's hydroplane hydroplane's hydroplaned hydroplanes hydroplaning hyena hyena's hyenas hygiene hygiene's hygienic hygienically hygienics hymn hymn's hymnal hymnal's hymnals hymned hymning hymns hype hype's hyped hyper hyperactive hyperactives hyperactivity hyperactivity's hyperbole hyperbole's hypersensitive hypertension hypertension's hyperventilate hyperventilated hyperventilates hyperventilating hypes hyphen hyphen's hyphenate hyphenated hyphenates hyphenating hyphenation hyphenation's hyphened hyphening hyphens hyping hypnosis hypnosis's hypnotic hypnotics hypnotise hypnotised hypnotises hypnotising hypnotism hypnotism's hypnotist hypnotist's hypnotists hypochondria hypochondria's hypochondriac hypochondriac's hypochondriacs hypocrisies hypocrisy hypocrisy's hypocrite hypocrite's hypocrites hypocritical hypocritically hypodermic hypodermics hypotenuse hypotenuse's hypotenuses hypothermia hypothermia's hypotheses hypothesis hypothesis's hypothesise hypothesised hypothesises hypothesising hypothetical hypothetically hysterectomies hysterectomy hysterectomy's hysteria hysteria's hysteric hysterical hysterically hysterics i ice ice's iceberg iceberg's icebergs icebox icebox's iceboxes icebreaker icebreaker's icebreakers iced ices icicle icicle's icicles icier iciest icing icing's icings ickier ickiest icky icon icon's icons icy id id's idea idea's ideal ideal's idealise idealised idealises idealising idealism idealism's idealist idealist's idealistic idealists ideally ideals ideas identical identically identifiable identification identification's identified identifier identifier's identifiers identifies identify identifying identities identity identity's ideological ideologically ideologies ideology ideology's idiocies idiocy idiocy's idiom idiom's idiomatic idioms idiosyncrasies idiosyncrasy idiosyncrasy's idiosyncratic idiot idiot's idiotic idiotically idiots idle idled idleness idleness's idler idles idlest idling idly idol idol's idolatrous idolatry idolatry's idolise idolised idolises idolising idols idyllic if iffier iffiest iffy ifs igloo igloo's igloos ignite ignited ignites igniting ignition ignition's ignitions ignorance ignorance's ignorant ignorants ignore ignored ignores ignoring iguana iguana's iguanas ilk ilk's ill illegal illegally illegals illegible illegibly illegitimacy illegitimacy's illegitimate illicit illiteracy illiteracy's illiterate illiterates illness illness's illnesses illogical illogically ills illuminate illuminated illuminates illuminating illumination illumination's illuminations illusion illusion's illusions illusory illustrate illustrated illustrates illustrating illustration illustration's illustrations illustrative illustrator illustrator's illustrators illustrious image image's imaged imagery imagery's images imaginable imaginary imagination imagination's imaginations imaginative imaginatively imagine imagined imagines imaging imagining imbalance imbalance's imbalanced imbalances imbecile imbecile's imbeciles imbibe imbibed imbibes imbibing imbue imbued imbues imbuing imitate imitated imitates imitating imitation imitation's imitations imitative imitator imitator's imitators immaculate immaculately immaterial immature immatures immaturity immaturity's immeasurable immeasurably immediacy immediacy's immediate immediately immense immensely immenser immensest immensities immensity immensity's immerse immersed immerses immersing immersion immersion's immersions immigrant immigrant's immigrants immigrate immigrated immigrates immigrating immigration immigration's imminent imminently immobile immobilise immobilised immobilises immobilising immobility immobility's immoral immoralities immorality immorality's immorally immortal immortalise immortalised immortalises immortalising immortality immortality's immortals immovable immune immunisation immunisation's immunisations immunise immunised immunises immunising immunity immunity's immutable imp imp's impact impact's impacted impacting impacts impair impaired impairing impairment impairment's impairments impairs impale impaled impales impaling impart imparted impartial impartiality impartiality's impartially imparting imparts impassable impasse impasse's impasses impassioned impassive impatience impatience's impatiences impatient impatiently impeach impeached impeaches impeaching impeachment impeachment's impeachments impeccable impeccables impeccably impedance impedance's impede impeded impedes impediment impediment's impediments impeding impel impelled impelling impels impend impended impending impends impenetrable imperative imperatives imperceptible imperceptibly imperfect imperfection imperfection's imperfections imperfectly imperfects imperial imperialism imperialism's imperialist imperialist's imperialists imperials imperil imperilled imperilling imperils impersonal impersonally impersonate impersonated impersonates impersonating impersonation impersonation's impersonations impersonator impersonator's impersonators impertinence impertinence's impertinent impertinents impervious impetuous impetuously impetus impetus's impetuses impinge impinged impinges impinging impish implacable implant implanted implanting implants implausible implement implement's implementable implementation implementation's implementations implemented implementer implementer's implementing implements implicate implicated implicates implicating implication implication's implications implicit implicitly implied implies implode imploded implodes imploding implore implored implores imploring imply implying impolite impolitely import importance importance's important importantly importation importation's importations imported importer importer's importers importing imports impose imposed imposes imposing imposition imposition's impositions impossibilities impossibility impossibility's impossible impossibles impossibly impostor impostor's impostors impotence impotence's impotent impound impounded impounding impounds impoverish impoverished impoverishes impoverishing impractical imprecise impregnable impregnate impregnated impregnates impregnating impress impressed impresses impressing impression impression's impressionable impressionistic impressions impressive impressively imprint imprint's imprinted imprinting imprints imprison imprisoned imprisoning imprisonment imprisonment's imprisonments imprisons improbabilities improbability improbability's improbable improbably impromptu impromptus improper improperly improprieties impropriety impropriety's improve improved improvement improvement's improvements improves improving improvisation improvisation's improvisations improvise improvised improvises improvising imps impudence impudence's impudent impulse impulse's impulsed impulses impulsing impulsive impulsively impulsiveness impulsiveness's impunity impunity's impure impurer impurest impurities impurity impurity's in inabilities inability inability's inaccessibility inaccessibility's inaccessible inaccuracies inaccuracy inaccuracy's inaccurate inaction inaction's inactive inactivity inactivity's inadequacies inadequacy inadequacy's inadequate inadequately inadequates inadmissible inadvertent inadvertently inadvisable inalienable inane inaner inanest inanimate inapplicable inappropriate inarticulate inarticulates inasmuch inattention inattention's inattentive inaudible inaudibly inaugural inaugurals inaugurate inaugurated inaugurates inaugurating inauguration inauguration's inaugurations inauspicious inborn inbred inbreds inbreed inbreeding inbreeding's inbreeds inbuilt incalculable incandescence incandescence's incandescent incandescents incantation incantation's incantations incapable incapacitate incapacitated incapacitates incapacitating incapacity incapacity's incarcerate incarcerated incarcerates incarcerating incarceration incarceration's incarcerations incarnate incarnated incarnates incarnating incarnation incarnation's incarnations incendiaries incendiary incense incense's incensed incenses incensing incentive incentive's incentives inception inception's inceptions incessant incessantly incest incest's incestuous inch inch's inched inches inching incidence incidence's incidences incident incident's incidental incidentally incidentals incidents incinerate incinerated incinerates incinerating incineration incineration's incinerator incinerator's incinerators incision incision's incisions incisive incisor incisor's incisors incite incited incitement incitement's incitements incites inciting inclination inclination's inclinations incline inclined inclines inclining include included includes including inclusion inclusion's inclusions inclusive incognito incognitos incoherence incoherence's incoherent incoherently income income's incomes incoming incomparable incompatibilities incompatibility incompatibility's incompatible incompatibles incompatibly incompetence incompetence's incompetent incompetently incompetents incomplete incompletely incomprehensible inconceivable inconclusive inconclusively incongruities incongruity incongruity's incongruous inconsequential inconsiderable inconsiderate inconsistencies inconsistency inconsistency's inconsistent inconsistently inconsolable inconspicuous inconspicuously incontinence incontinence's incontinent inconvenience inconvenience's inconvenienced inconveniences inconveniencing inconvenient inconveniently incorporate incorporated incorporates incorporating incorporation incorporation's incorrect incorrectly incorrigible increase increased increases increasing increasingly increasings incredible incredibly incredulity incredulity's incredulous increment increment's incremental incremented incrementing increments incriminate incriminated incriminates incriminating incrimination incrimination's incubate incubated incubates incubating incubation incubation's incubator incubator's incubators incumbent incumbents incur incurable incurables incurably incurred incurring incurs indebted indebtedness indebtedness's indecencies indecency indecency's indecent indecenter indecentest indecently indecision indecision's indecisive indecisively indeed indeeds indefensible indefinable indefinably indefinite indefinitely indefinites indelible indelibly indelicate indemnified indemnifies indemnify indemnifying indemnities indemnity indemnity's indent indentation indentation's indentations indented indenting indents independence independence's independent independently independents indescribable indescribables indescribably indestructible indeterminate index index's indexed indexes indexing indicate indicated indicates indicating indication indication's indications indicative indicatives indicator indicator's indicators indices indices's indict indicted indicting indictment indictment's indictments indicts indifference indifference's indifferent indifferently indigenous indigent indigents indigestible indigestibles indigestion indigestion's indignant indignantly indignation indignation's indignities indignity indignity's indigo indigo's indirect indirection indirection's indirectly indirectness indirectness's indiscreet indiscretion indiscretion's indiscretions indiscriminate indiscriminately indispensable indispensables indisposed indisputable indistinct indistinctly indistinguishable individual individualism individualism's individualist individualist's individualistic individualists individuality individuality's individually individuals indivisible indoctrinate indoctrinated indoctrinates indoctrinating indoctrination indoctrination's indolence indolence's indolent indomitable indoor indoors induce induced inducement inducement's inducements induces inducing induct inducted inducting induction induction's inductions inducts indulge indulged indulgence indulgence's indulgences indulgent indulges indulging industrial industrialisation industrialisation's industrialise industrialised industrialises industrialising industrialist industrialist's industrialists industries industrious industry industry's inebriate inebriated inebriates inebriating inebriation inebriation's inedible ineffective ineffectiveness ineffectiveness's ineffectual inefficiencies inefficiency inefficiency's inefficient inefficiently inefficients inelegant ineligibility ineligibility's ineligible ineligibles inept ineptitude ineptitude's inequalities inequality inequality's inequities inequity inequity's inert inertia inertia's inertial inerts inescapable inessential inessentials inevitability inevitability's inevitable inevitably inexact inexcusable inexhaustible inexorable inexorably inexpensive inexpensively inexperience inexperience's inexperienced inexplicable inexplicably inextricably infallibility infallibility's infallible infamies infamous infamy infamy's infancy infancy's infant infant's infantile infantries infantry infantry's infants infatuate infatuated infatuates infatuating infatuation infatuation's infatuations infect infected infecting infection infection's infections infectious infects infelicities infelicity infelicity's infer inference inference's inferences inferior inferiority inferiority's inferiors inferno inferno's infernos inferred inferring infers infertile infertility infertility's infest infestation infestation's infestations infested infesting infests infidel infidel's infidelities infidelity infidelity's infidels infield infield's infielder infielder's infielders infields infiltrate infiltrated infiltrates infiltrating infiltration infiltration's infiltrator infiltrator's infiltrators infinite infinitely infinitesimal infinitesimals infinities infinitive infinitive's infinitives infinity infinity's infirm infirmaries infirmary infirmary's infirmities infirmity infirmity's infix inflame inflamed inflames inflaming inflammable inflammation inflammation's inflammations inflammatory inflatable inflatable's inflatables inflate inflated inflates inflating inflation inflation's inflationary inflection inflection's inflections inflexibility inflexibility's inflexible inflexibly inflict inflicted inflicting infliction infliction's inflicts influence influence's influenced influences influencing influential influenza influenza's influx influx's influxes info info's infomercial infomercials inform informal informality informality's informally informant informant's informants information information's informational informative informed informer informer's informers informing informs infraction infraction's infractions infrared infrared's infrastructure infrastructure's infrastructures infrequent infrequently infringe infringed infringement infringement's infringements infringes infringing infuriate infuriated infuriates infuriating infuriatingly infuse infused infuses infusing infusion infusion's infusions ingenious ingeniously ingenuity ingenuity's ingest ingested ingesting ingests ingrain ingrained ingraining ingrains ingratiate ingratiated ingratiates ingratiating ingratitude ingratitude's ingredient ingredient's ingredients inhabit inhabitant inhabitant's inhabitants inhabited inhabiting inhabits inhalation inhalation's inhalations inhale inhaled inhaler inhaler's inhalers inhales inhaling inherent inherently inherit inheritance inheritance's inheritances inherited inheriting inherits inhibit inhibited inhibiting inhibition inhibition's inhibitions inhibits inhospitable inhuman inhumane inhumanities inhumanity inhumanity's initial initialisation initialise initialised initialises initialising initialled initialling initially initials initiate initiated initiates initiating initiation initiation's initiations initiative initiative's initiatives initiator initiator's initiators inject injected injecting injection injection's injections injects injunction injunction's injunctions injure injured injures injuries injuring injurious injury injury's injustice injustice's injustices ink ink's inked inkier inkiest inking inkling inkling's inks inky inlaid inland inlay inlaying inlays inlet inlet's inlets inmate inmate's inmates inn inn's innards innate inned inner innermost inners inning inning's innings innkeeper innkeeper's innkeepers innocence innocence's innocent innocenter innocentest innocently innocents innocuous innovate innovated innovates innovating innovation innovation's innovations innovative innovator innovator's innovators inns innuendo innuendo's innuendoed innuendoes innuendoing innuendos innumerable inoculate inoculated inoculates inoculating inoculation inoculation's inoculations inoffensive inoperative inopportune inordinate inordinately inorganic inpatient inpatient's inpatients input input's inputs inputted inputting inquest inquest's inquests inquisition inquisition's inquisitions inquisitive inroad inroads ins insane insanely insaner insanest insanity insanity's insatiable inscribe inscribed inscribes inscribing inscription inscription's inscriptions inscrutable insect insect's insecticide insecticide's insecticides insects insecure insecurities insecurity insecurity's insemination insemination's insensitive insensitively insensitivity insensitivity's inseparable inseparables insert inserted inserting insertion insertion's insertions inserts inside inside's insider insider's insiders insides insidious insight insight's insights insigne insignia insignia's insignias insignificance insignificance's insignificant insignificantly insincere insincerely insincerity insincerity's insinuate insinuated insinuates insinuating insinuation insinuation's insinuations insipid insist insisted insistence insistence's insistent insistently insisting insists insofar insolence insolence's insolent insoluble insolubles insolvency insolvency's insolvent insolvents insomnia insomnia's insomniac insomniacs inspect inspected inspecting inspection inspection's inspections inspector inspector's inspectors inspects inspiration inspiration's inspirational inspirations inspire inspired inspires inspiring instability instability's instal install installation installation's installations installed installing installs instalment instalment's instalments instals instance instance's instanced instances instancing instant instant's instantaneous instantaneously instantly instants instead instep instep's insteps instigate instigated instigates instigating instigation instigation's instil instill instilled instilling instills instils instinct instinct's instinctive instinctively instincts institute instituted institutes institutes's instituting institution institution's institutional institutionalise institutionalised institutionalises institutionalising institutions instruct instructed instructing instruction instruction's instructions instructive instructively instructor instructor's instructors instructs instrument instrument's instrumental instrumentals instrumented instrumenting instruments insubordinate insubordination insubordination's insubstantial insufferable insufficiency insufficiency's insufficient insufficiently insular insularity insularity's insulate insulated insulates insulating insulation insulation's insulator insulator's insulators insulin insulin's insult insulted insulting insults insurance insurance's insurances insure insured insureds insurer insurers insures insurgencies insurgency insurgency's insurgent insurgents insuring insurmountable insurrection insurrection's insurrections intact intake intake's intakes intangible intangibles integer integer's integers integral integrals integrate integrated integrates integrating integration integration's integrity integrity's intellect intellect's intellects intellectual intellectually intellectuals intelligence intelligence's intelligent intelligently intelligible intelligibly intend intended intendeds intending intends intense intensely intenser intensest intensified intensifier intensifier's intensifiers intensifies intensify intensifying intensities intensity intensity's intensive intensively intensives intent intent's intention intention's intentional intentionally intentions intently intents inter interact interacted interacting interaction interaction's interactions interactive interactively interacts intercede interceded intercedes interceding intercept intercepted intercepting interception interception's interceptions intercepts interchange interchangeable interchangeably interchanged interchanges interchanging intercom intercom's intercoms interconnect interconnected interconnecting interconnects intercontinental intercourse intercourse's interdependence interdependence's interdependent interest interest's interested interesting interestingly interests interface interface's interfaced interfaces interfacing interfacing's interfere interfered interference interference's interferes interfering interim interior interior's interiors interject interjected interjecting interjection interjection's interjections interjects interlock interlocked interlocking interlocks interloper interloper's interlopers interlude interlude's interluded interludes interluding intermarriage intermarriage's intermarriages intermarried intermarries intermarry intermarrying intermediaries intermediary intermediary's intermediate intermediates interment interment's interments interminable interminably intermingle intermingled intermingles intermingling intermission intermission's intermissions intermittent intermittently intern internal internally internals international internationally internationals interned interning internist internist's internists internment internment's interns internship internship's internships interpersonal interplanetary interplay interplay's interpolation interpolation's interpose interposed interposes interposing interpret interpretation interpretation's interpretations interpreted interpreter interpreter's interpreters interpreting interprets interracial interred interrelate interrelated interrelates interrelating interring interrogate interrogated interrogates interrogating interrogation interrogation's interrogations interrogator interrogator's interrogators interrupt interrupted interrupting interruption interruption's interruptions interrupts inters intersect intersected intersecting intersection intersection's intersections intersects intersperse interspersed intersperses interspersing interstate interstates interstellar intertwine intertwined intertwines intertwining interval interval's intervals intervene intervened intervenes intervening intervention intervention's interventions interview interview's interviewed interviewer interviewer's interviewers interviewing interviews interweave interweaved interweaves interweaving interwove interwoven intestate intestinal intestine intestine's intestines inti intimacies intimacy intimacy's intimate intimated intimately intimates intimating intimation intimation's intimations intimidate intimidated intimidates intimidating intimidation intimidation's into intolerable intolerably intolerance intolerance's intolerant intonation intonation's intonations intoxicate intoxicated intoxicates intoxicating intoxication intoxication's intractable intramural intransitive intransitively intransitives intravenous intravenouses intrepid intricacies intricacy intricacy's intricate intricately intrigue intrigued intrigues intriguing intrinsic intrinsically introduce introduced introduces introducing introduction introduction's introductions introductory introspective introvert introvert's introverted introverts intrude intruded intruder intruder's intruders intrudes intruding intrusion intrusion's intrusions intrusive intrusives intuition intuition's intuitions intuitive intuitively inundate inundated inundates inundating inundation inundation's inundations invade invaded invader invader's invaders invades invading invalid invalid's invalidate invalidated invalidates invalidating invalided invaliding invalids invaluable invariable invariables invariably invariant invariant's invasion invasion's invasions invasive invective invective's invent invented inventing invention invention's inventions inventive inventor inventor's inventoried inventories inventors inventory inventory's inventorying invents inverse inversely inverses inversion inversion's inversions invert invertebrate invertebrate's invertebrates inverted inverting inverts invest invested investigate investigated investigates investigating investigation investigation's investigations investigative investigator investigator's investigators investing investment investment's investments investor investor's investors invests inveterate invigorate invigorated invigorates invigorating invincible invisibility invisibility's invisible invisibly invitation invitation's invitations invite invited invites inviting invocation invocation's invocations invoice invoice's invoiced invoices invoicing invoke invoked invokes invoking involuntarily involuntary involve involved involvement involvement's involvements involves involving invulnerable inward inwardly inwards iodine iodine's ion ion's ions iota iota's iotas irascible irate irater iratest ire ire's ired ires iridescence iridescence's iridescent iring iris iris's irises irk irked irking irks iron iron's ironed ironic ironically ironies ironing ironing's irons irony irony's irradiate irradiated irradiates irradiating irrational irrationality irrationality's irrationally irrationals irreconcilable irrefutable irregular irregularities irregularity irregularity's irregularly irregulars irrelevance irrelevance's irrelevances irrelevant irreparable irreparably irreplaceable irrepressible irreproachable irresistible irresistibly irrespective irresponsibility irresponsibility's irresponsible irresponsibly irretrievable irretrievably irreverence irreverence's irreverent irreverently irreversible irrevocable irrevocably irrigate irrigated irrigates irrigating irrigation irrigation's irritability irritability's irritable irritably irritant irritants irritate irritated irritates irritating irritation irritation's irritations is island island's islander islander's islanders islands isle isle's isles isn't isolate isolated isolates isolating isolation isolation's issue issue's issued issues issuing isthmi isthmus isthmus's isthmuses it it'd it'll it's italic italicise italicised italicises italicising italics itch itch's itched itches itchier itchiest itchiness itchiness's itching itchy item item's itemise itemised itemises itemising items iterate iteration iteration's iterations iterative itinerant itinerants itineraries itinerary itinerary's its itself ivies ivories ivory ivory's ivy ivy's j jab jabbed jabber jabbered jabbering jabbers jabbing jabs jack jack's jackal jackal's jackals jackass jackass's jackasses jackdaw jackdaw's jacked jacket jacket's jackets jackhammer jackhammer's jackhammered jackhammering jackhammers jacking jackknife jackknife's jackknifed jackknifes jackknifing jackknives jackpot jackpot's jackpots jacks jade jade's jaded jades jading jagged jaggeder jaggedest jaguar jaguar's jaguars jail jail's jailed jailer jailer's jailers jailing jails jalopies jalopy jalopy's jam jam's jamb jamb's jambed jambing jamboree jamboree's jamborees jambs jammed jamming jams jangle jangled jangles jangling janitor janitor's janitors jar jar's jargon jargon's jarred jarring jars jaundice jaundice's jaundiced jaundices jaundicing jaunt jaunt's jaunted jauntier jaunties jauntiest jauntily jaunting jaunts jaunty javelin javelin's javelins jaw jaw's jawbone jawbone's jawboned jawbones jawboning jawed jawing jaws jay jay's jays jaywalk jaywalked jaywalker jaywalker's jaywalkers jaywalking jaywalks jazz jazz's jazzed jazzes jazzier jazziest jazzing jazzy jealous jealousies jealously jealousy jealousy's jeans jeer jeered jeering jeers jeez jell jelled jellied jellies jelling jells jelly jelly's jellyfish jellyfish's jellyfishes jellying jeopardise jeopardised jeopardises jeopardising jeopardy jeopardy's jerk jerked jerkier jerkiest jerkily jerking jerks jerky jersey jersey's jerseys jest jest's jested jester jester's jesters jesting jests jet jet's jets jetted jetties jetting jettison jettisoned jettisoning jettisons jetty jetty's jewel jewel's jewelled jeweller jeweller's jewellers jewelling jewelries jewelry jewelry's jewels jibe jibed jibes jibing jiffies jiffy jiffy's jig jig's jigged jigger jigger's jiggered jiggering jiggers jigging jiggle jiggled jiggles jiggling jigs jigsaw jigsaw's jigsawed jigsawing jigsawn jigsaws jilt jilted jilting jilts jingle jingled jingles jingling jinx jinx's jinxed jinxes jinxing jitterier jitteriest jitters jittery jive jive's jived jives jiving job job's jobbed jobbing jobless joblessness joblessness's jobs jock jock's jocked jockey jockey's jockeyed jockeying jockeys jocking jocks jockstrap jockstrap's jockstraps jocular jocularity jocularity's jog jogged jogger jogger's joggers jogging jogs john john's johns join joined joining joins joint joint's jointed jointing jointly joints joke joke's joked joker joker's jokers jokes joking jollied jollier jollies jolliest jolly jollying jolt jolted jolting jolts jostle jostled jostles jostling jot jots jotted jotting journal journal's journalism journalism's journalist journalist's journalists journals journey journey's journeyed journeying journeys jovial jovially jowl jowls joy joy's joyed joyful joyfuller joyfullest joyfully joyfulness joyfulness's joying joyous joyously joyridden joyride joyride's joyrider joyriders joyrides joyriding joyrode joys joystick joysticks jubilant jubilation jubilation's jubilee jubilee's jubilees judge judge's judged judgement judgement's judgemental judgements judges judging judicial judicially judiciaries judiciary judicious judiciously judo judo's jug jug's jugged juggernaut juggernaut's jugging juggle juggled juggler juggler's jugglers juggles juggling jugs jugular jugulars juice juice's juiced juices juicier juiciest juicing juicy jukebox jukebox's jukeboxes jumble jumbled jumbles jumbling jumbo jumbo's jumbos jump jumped jumper jumper's jumpers jumpier jumpiest jumping jumps jumpsuit jumpsuits jumpy junction junction's junctions juncture juncture's junctures jungle jungle's jungles junior juniors juniper juniper's junipers junk junk's junked junket junket's junketed junketing junkets junkie junkie's junkier junkies junkiest junking junks junky junkyard junkyard's junkyards junta junta's juntas juries jurisdiction jurisdiction's juror juror's jurors jury jury's just juster justest justice justice's justices justifiable justifiably justification justification's justifications justified justifies justify justifying justly jut jute jute's juts jutted jutting juvenile juveniles juxtapose juxtaposed juxtaposes juxtaposing juxtaposition juxtaposition's juxtapositions k kW kaleidoscope kaleidoscope's kaleidoscopes kangaroo kangaroo's kangarooed kangarooing kangaroos kaput kaput's karat karat's karate karate's karats karma karma's kayak kayak's kayaked kayaking kayaks keel keel's keeled keeling keels keen keened keener keenest keening keenly keenness keenness's keens keep keeper keeper's keepers keeping keeping's keeps keepsake keepsake's keepsakes keg keg's kegged kegging kegs kelp kelp's ken ken's kennel kennel's kennelled kennelling kennels kept kerb kerb's kerbed kerbing kerbs kerchief kerchief's kerchiefed kerchiefing kerchiefs kerchieves kernel kernel's kernels kerosene kerosene's ketchup ketchup's kettle kettle's kettles key key's keyboard keyboard's keyboarded keyboarding keyboards keyed keyhole keyhole's keyholes keying keynote keynote's keynoted keynotes keynoting keys keystone keystone's keystones keystroke keystroke's keystrokes keyword keyword's keywords khaki khaki's khakis kick kickback kickback's kickbacks kicked kicking kickoff kickoff's kickoffs kicks kid kid's kidded kiddie kiddied kiddies kidding kidding's kiddo kiddo's kiddoes kiddos kiddy kiddying kidnap kidnaped kidnaping kidnapped kidnapper kidnapper's kidnappers kidnapping kidnappings kidnaps kidney kidney's kidneys kids kill killed killer killer's killers killing killings kills kiln kiln's kilned kilning kilns kilo kilo's kilobyte kilobytes kilogramme kilogramme's kilogrammes kilometre kilometre's kilometres kilos kilowatt kilowatt's kilowatts kilt kilt's kilts kimono kimono's kimonos kin kin's kind kinda kinder kindergarten kindergarten's kindergartens kindergrtner kindergrtner's kindergrtners kindest kindhearted kindle kindled kindles kindlier kindliest kindling kindling's kindly kindness kindness's kindnesses kindred kinds kinfolk king king's kingdom kingdom's kingdoms kingfisher kingfisher's kingfishers kingpin kingpin's kingpins kings kink kink's kinked kinkier kinkiest kinking kinks kinky kins kinship kinship's kiosk kiosk's kiosks kipper kipper's kiss kissed kisses kissing kit kit's kitchen kitchen's kitchened kitchenette kitchenette's kitchenettes kitchening kitchens kite kite's kited kites kiting kits kitten kitten's kittens kitties kitty kitty's kiwi kiwi's kiwis kleptomaniac kleptomaniac's kleptomaniacs klutz klutz's klutzes klutzier klutziest klutzy knack knack's knacked knacker knacker's knacking knacks knapsack knapsack's knapsacks knead kneaded kneading kneads knee knee's kneecap kneecap's kneecapped kneecapping kneecaps kneed kneeing kneel kneeled kneeling kneels knees knelt knew knickers knickknack knickknack's knickknacks knife knife's knifed knifes knifing knight knight's knighted knighthood knighthood's knighthoods knighting knights knit knits knitted knitting knitting's knives knives's knob knob's knobbier knobbiest knobby knobs knock knocked knocker knocker's knockers knocking knockout knockout's knockouts knocks knoll knoll's knolls knot knot's knots knotted knottier knottiest knotting knotty know knowing knowinger knowingest knowingly knowings knowledge knowledge's knowledgeable knowledgeably known knows knuckle knuckle's knuckled knuckles knuckling koala koala's koalas kosher koshered koshering koshers kowtow kowtowed kowtowing kowtows ks kudos kudos's l lab lab's label label's labelled labelling labels laboratories laboratory laboratory's laborious laboriously labour labour's laboured labourer labourer's labourers labouring labours labs labyrinth labyrinth's labyrinths lace lace's laced lacerate lacerated lacerates lacerating laceration laceration's lacerations laces lacier laciest lacing lack lack's lacked lacking lacklustre lacks lacquer lacquer's lacquered lacquering lacquers lacrosse lacrosse's lacy lad lad's ladder ladder's laddered laddering ladders lade laded laden lades ladies lading ladle ladle's ladled ladles ladling lads lady lady's ladybug ladybug's ladybugs ladylike lag lager lager's laggard laggard's laggards lagged lagging lagging's lagoon lagoon's lagoons lags laid lain lair lair's lairs lake lake's laked lakes laking lamb lamb's lambda lambda's lambed lambing lambs lame lamed lament lamentable lamentation lamentation's lamentations lamented lamenting laments lamer lames lamest laminate laminated laminates laminating laming lamp lamp's lampoon lampoon's lampooned lampooning lampoons lamps lampshade lampshade's lampshades lance lance's lanced lances lancing land land's landed lander landfill landfills landing landing's landings landladies landlady landlady's landlocked landlord landlord's landlords landmark landmark's landmarks landowner landowner's landowners lands landscape landscape's landscaped landscapes landscaping landslid landslidden landslide landslide's landslides landsliding lane lane's lanes language language's languages languid languish languished languishes languishing languor languor's languorous languors lankier lankiest lanky lantern lantern's lanterns lap lap's lapel lapel's lapels lapped lapping laps lapse lapse's lapsed lapses lapsing laptop laptops larcenies larceny larceny's lard lard's larded larding lards large largely larger larges largest lark lark's larked larking larks larva larva's larvae larvas larynges laryngitis laryngitis's larynx larynx's larynxes lascivious laser laser's lasers lash lash's lashed lashes lashing lass lass's lasses lasso lasso's lassoed lassoes lassoing lassos last lasted lasting lastly lasts latch latch's latched latches latching late lately latent latents later lateral lateraled lateraling lateralled lateralling laterals latest latex latex's lath lathe lathe's lathed lather lather's lathered lathering lathers lathes lathing laths latitude latitude's latitudes latrine latrine's latrines latter lattice lattice's lattices laud laudable lauded lauding lauds laugh laughable laughed laughing laughing's laughingstock laughingstock's laughingstocks laughs laughter laughter's launch launched launcher launchers launches launching launder laundered laundering launders laundries laundry laundry's laureate laureated laureates laureating laurel laurel's laurels lava lava's lavatories lavatory lavatory's lavender lavender's lavendered lavendering lavenders lavish lavished lavisher lavishes lavishest lavishing law law's lawful lawless lawlessness lawlessness's lawmaker lawmaker's lawmakers lawn lawn's lawns laws lawsuit lawsuit's lawsuits lawyer lawyer's lawyers lax laxative laxative's laxatives laxer laxes laxest laxity laxity's lay layaway layer layer's layered layering layers laying layman layman's laymen layoff layoff's layoffs layout layout's layouts layover layover's layovers lays lazied lazier lazies laziest lazily laziness laziness's lazy lazying leach lead leaded leaden leader leader's leaders leadership leadership's leading leads leaf leaf's leafed leafier leafiest leafing leaflet leaflet's leafleted leafleting leaflets leafletted leafletting leafs leafy league league's leagued leagues leaguing leak leak's leakage leakage's leakages leaked leakier leakiest leaking leaks leaky lean leaned leaner leanest leaning leaning's leanings leans leant leap leaped leapfrog leapfrog's leapfrogged leapfrogging leapfrogs leaping leaps leapt learn learning learning's learns learnt lease lease's leased leases leash leash's leashed leashes leashing leasing least leather leather's leathery leave leaved leaves leaves's leaving leaving's lecherous lectern lectern's lecterns lecture lecture's lectured lecturer lecturer's lecturers lectures lecturing led ledge ledge's ledger ledger's ledgered ledgering ledgers ledges lee lee's leech leech's leeched leeches leeching leek leek's leeks leer leered leerier leeriest leering leers leery leeway leeway's left lefter leftest leftmost leftover leftovers lefts leg leg's legacies legacy legacy's legal legalise legalised legalises legalising legalistic legality legality's legally legals legend legend's legendary legends legged leggier leggiest legging leggings leggy legibility legibility's legible legibly legion legion's legions legislate legislated legislates legislating legislation legislation's legislative legislator legislator's legislators legislature legislature's legislatures legit legitimacy legitimacy's legitimate legitimated legitimately legitimates legitimating legs legume legume's legumes leisure leisure's leisurely lemme lemon lemon's lemonade lemonade's lemoned lemoning lemons lend lender lender's lenders lending lends length length's lengthen lengthened lengthening lengthens lengthier lengthiest lengths lengthwise lengthy leniency leniency's lenient leniently lenients lens lens's lenses lent lentil lentil's lentils leopard leopard's leopards leotard leotard's leotards leper leper's lepers leprosy leprosy's leprous lept les lesbian lesbian's lesbianism lesbianism's lesbians lesion lesion's lesions less lessen lessened lessening lessens lesser lesson lesson's lessons lest let let's letdown letdown's letdowns lethal lethally lethals lethargic lethargy lethargy's lets letter letter's lettered letterhead letterhead's letterheads lettering letters letting lettuce lettuce's lettuces letup letup's letups leukaemia leukaemia's levee levee's levees level levelheaded levelled leveller levellest levelling levels lever lever's leverage leverage's leveraged leverages leveraging levered levering levers levied levies levitate levitated levitates levitating levitation levitation's levity levity's levy levying lewd lewder lewdest lexica lexical lexicon lexicon's lexicons liabilities liability liability's liable liaise liaised liaises liaising liaison liaison's liaisons liar liar's liars lib lib's libbed libbing libel libel's libelled libelling libellous libels liberal liberalisation liberalisation's liberalise liberalised liberalises liberalising liberalism liberalism's liberally liberals liberate liberated liberates liberating liberation liberation's libertarian libertarian's liberties liberty liberty's libido libido's libidos librarian librarian's librarians libraries library library's libretto libretto's libs lice lice's licence licence's licenced licences licencing license license's licensed licenses licensing lichen lichen's lichens lick licked licking licking's lickings licks licorice licorice's licorices lid lid's lids lie lied lied's lien lien's liens lies lieu lieu's lieutenant lieutenant's lieutenants life life's lifeboat lifeboat's lifeboats lifeforms lifeguard lifeguard's lifeguards lifeless lifelike lifeline lifeline's lifelines lifelong lifesaver lifesaver's lifesavers lifespan lifestyle lifestyles lifetime lifetime's lifetimes lift lift's lifted lifting liftoff liftoff's liftoffs lifts ligament ligament's ligaments ligature ligatures light light's lighted lighten lightened lightening lightens lighter lighter's lighters lightest lighthearted lighthouse lighthouse's lighthouses lighting lighting's lightly lightness lightness's lightning lightning's lightninged lightnings lights lightweight lightweights likable like liked likelier likeliest likelihood likelihood's likelihoods likely liken likened likeness likeness's likenesses likening likens liker likes likest likewise liking liking's lilac lilac's lilacs lilies lilt lilt's lilted lilting lilts lily lily's limb limb's limber limbered limberer limberest limbering limbers limbo limbo's limboed limboing limbos limbs lime lime's limed limelight limelight's limelighted limelighting limelights limerick limerick's limericks limes limestone limestone's liming limit limit's limitation limitation's limitations limited limiting limitings limitless limits limo limos limousine limousine's limousines limp limped limper limpest limping limps linchpin linchpin's linchpins line line's lineage lineage's lineages linear linearly lined linefeed linen linen's linens liner liner's liners lines lineup lineups linger lingered lingerie lingerie's lingering lingers lingo lingo's lingoes lingos linguist linguist's linguistic linguistics linguistics's linguists liniment liniment's liniments lining lining's linings link link's linkage linkage's linkages linked linker linking links linoleum linoleum's lint lint's lints lion lion's lioness lioness's lionesses lions lip lip's lips lipstick lipstick's lipsticked lipsticking lipsticks liquefied liquefies liquefy liquefying liqueur liqueur's liqueured liqueuring liqueurs liquid liquid's liquidate liquidated liquidates liquidating liquidation liquidation's liquidations liquids liquor liquor's liquored liquoring liquors lisp lisp's lisped lisping lisps list list's listed listen listened listener listener's listeners listening listens listing listing's listings listless listlessly lists lit litanies litany litany's lite literacy literacy's literal literally literals literary literate literates literature literature's lites lithe lither lithest lithium lithium's litigate litigated litigates litigating litigation litigation's litre litre's litres litter litter's litterbug litterbug's litterbugs littered littering litters little littler littlest liturgical liturgies liturgy liturgy's livable live lived livelier liveliest livelihood livelihood's livelihoods liveliness liveliness's lively liven livened livening livens liver liver's livers lives lives's livest livestock livestock's livid living livings lizard lizard's lizards llama llama's llamas load load's loadable loaded loader loader's loading loading's loads loaf loaf's loafed loafer loafer's loafers loafing loafs loam loam's loan loan's loaned loaning loans loath loathe loathed loather loathes loathing loathing's loathings loathsome loaves loaves's lob lob's lobbed lobbied lobbies lobbing lobby lobby's lobbying lobbyist lobbyist's lobbyists lobe lobe's lobed lobes lobing lobotomy lobotomy's lobs lobster lobster's lobstered lobstering lobsters local locale locale's localed locales localing localise localised localises localising localities locality locality's localled localling locally locals locate located locates locating location location's locations lock lock's locked locker locker's lockers locket locket's lockets locking locks locksmith locksmith's locksmiths locomotion locomotion's locomotive locomotive's locomotives locust locust's locusts lodge lodge's lodged lodger lodger's lodgers lodges lodging lodging's lodgings loft loft's lofted loftier loftiest loftiness loftiness's lofting lofts lofty log log's logarithm logarithm's logarithmic logbook logbook's logbooks logged logger logger's logging logging's logic logic's logical logically logician logician's logistical logistics logjam logjam's logjams logo logo's logos logs loin loin's loincloth loincloth's loincloths loins loiter loitered loiterer loiterer's loiterers loitering loiters loll lolled lolling lollipop lollipop's lollipops lolls lone lonelier loneliest loneliness loneliness's lonely loner loner's loners lonesome lonesomes long longed longer longest longevity longevity's longhand longhand's longing longing's longingly longings longish longitude longitude's longitudes longitudinal longs longshoreman longshoreman's longshoremen longtime look lookalike lookalikes looked looking lookout lookout's lookouts looks loom loom's loomed looming looms loon loon's looney looneys loonier loonies looniest loons loony loop loop's looped loophole loophole's loopholes looping loops loose loosed loosely loosen loosened loosening loosens looser looses loosest loosing loosing's loot loot's looted looter looter's looters looting loots lop lope loped lopes loping lopped lopping lops lopsided lord lord's lorded lording lords lore lore's lorries lorry lorry's lose loser loser's losers loses losing loss loss's losses lost lot lotion lotion's lotions lots lotteries lottery lottery's lotus lotus's lotuses loud louder loudest loudlier loudliest loudly loudmouth loudmouth's loudmouthed loudmouths loudness loudness's loudspeaker loudspeaker's loudspeakers lounge lounged lounges lounging louse louse's loused louses lousier lousiest lousing lousy lovable love loved lovelier lovelies loveliest loveliness loveliness's lovely lover lover's lovers loves lovesick loving lovingly lovings low lowbrow lowbrow's lowbrows lowdown lowed lower lowercase lowered lowering lowers lowest lowing lowlier lowliest lowly lows loyal loyaler loyalest loyaller loyallest loyally loyalties loyalty loyalty's lozenge lozenge's lozenges ls lubricant lubricant's lubricants lubricate lubricated lubricates lubricating lubrication lubrication's lucid lucidity lucidity's lucidly luck luck's lucked luckier luckiest luckily lucking lucks lucky lucrative ludicrous ludicrously lug luggage luggage's lugged lugging lugs lugubrious lukewarm lull lullabies lullaby lullaby's lulled lulling lulls lumber lumber's lumbered lumbering lumbering's lumberjack lumberjack's lumberjacks lumbers lumberyard lumberyard's lumberyards luminaries luminary luminary's luminous lump lump's lumped lumpier lumpiest lumping lumps lumpy lunacies lunacy lunacy's lunar lunatic lunatics lunch lunch's lunchbox lunchboxes lunched luncheon luncheon's luncheoned luncheoning luncheons lunches lunching lunchtime lunchtime's lunchtimes lung lung's lunge lunge's lunged lunges lunging lungs lupin lupins lurch lurched lurches lurching lure lured lures lurid luridly luring lurk lurked lurking lurks luscious lush lusher lushes lushest lust lust's lusted luster luster's lustier lustiest lusting lustre lustre's lustrous lusts lusty lute lute's lutes luxuriant luxuriate luxuriated luxuriates luxuriating luxuries luxurious luxuriously luxury luxury's lye lye's lying lymph lymph's lymphatic lymphatics lynch lynched lynches lynching lynching's lynchings lyre lyre's lyres lyric lyrical lyricist lyricist's lyricists lyrics m ma ma'am ma's macabre macaroni macaroni's mace mace's maced maces machete machete's machetes machine machine's machined machinery machinery's machines machining machinist machinist's machinists macho macing macintosh macintosh's mackerel mackerel's mackerels macro macro's macrocosm macrocosm's macrocosms macros macroscopic mad madam madam's madame madame's madams madcap madcaps madden maddened maddening maddeningly maddens madder maddest made madhouse madhouse's madhouses madly madman madman's madmen madness madness's maelstrom maelstrom's maelstroms magazine magazine's magazines magenta magenta's maggot maggot's maggots magic magic's magical magically magician magician's magicians magicked magicking magics magistrate magistrate's magistrates magnanimity magnanimity's magnanimous magnanimously magnate magnate's magnates magnesium magnesium's magnet magnet's magnetic magnetics magnetise magnetised magnetises magnetising magnetism magnetism's magnets magnification magnification's magnifications magnificence magnificence's magnificent magnificently magnified magnifies magnify magnifying magnitude magnitude's magnitudes magnolia magnolia's magnolias magnum magnum's magpie magpie's magpies mahoganies mahogany mahogany's maid maid's maiden maiden's maidens maids mail mail's mailbox mailbox's mailboxes mailed mailing mailings mailman mailman's mailmen mails maim maimed maiming maims main mainframe mainframes mainland mainland's mainlands mainline mainly mains mains's mainstay mainstay's mainstays mainstream mainstream's mainstreamed mainstreaming mainstreams maintain maintainability maintainable maintained maintainer maintainer's maintainers maintaining maintains maintenance maintenance's maize maize's maizes majestic majestically majesties majesty majesty's major major's majored majoring majorities majority majority's majorly majors make maker maker's makers makes makeshift makeshifts makeup makeup's makeups making making's maladies maladjusted malady malady's malaise malaise's malaria malaria's male males malevolence malevolent malformed malfunction malfunctioned malfunctioning malfunctions malice malice's maliced malices malicing malicious maliciously malign malignancies malignancy malignancy's malignant malignants maligned maligning maligns mall mall's mallard mallard's mallards malleable malled mallet mallet's mallets malling malls malnourished malnutrition malnutrition's malpractice malpractice's malpractices malt malt's malted malting maltreat maltreated maltreating maltreats malts mama mama's mamas mammal mammal's mammalian mammalian's mammals mammoth mammoth's mammoths man man's manacle manacle's manacled manacles manacling manage manageable managed management management's manager manager's managerial managers manages managing mandarin mandarin's mandarins mandate mandate's mandated mandates mandating mandatory mandible mandible's mandibles mandolin mandolin's mandolins mane mane's manes mange mange's manged manger manger's mangers manges mangier mangiest manging mangle mangled mangles mangling mango mango's mangoes mangos mangrove mangrove's mangroves mangy manhandle manhandled manhandles manhandling manhole manhole's manholes manhood manhood's manhunt manhunt's manhunts mania mania's maniac maniac's maniacal maniacs manias manic manics manicure manicure's manicured manicures manicuring manicurist manicurist's manicurists manifest manifestation manifestation's manifestations manifested manifesting manifestly manifesto manifesto's manifestoed manifestoes manifestoing manifestos manifests manifold manifolded manifolding manifolds manipulate manipulated manipulates manipulating manipulation manipulations manipulative manipulative's mankind mankind's manlier manliest manliness manliness's manly manned mannequin mannequin's mannequins manner manner's mannerism mannerism's mannerisms manners manning mannish manoeuvre manoeuvre's manoeuvred manoeuvres manoeuvring manor manor's manors manpower manpower's mans mansion mansion's mansions manslaughter manslaughter's mantel mantel's mantelpiece mantelpiece's mantelpieces mantels mantle mantle's mantled mantles mantling mantra mantra's mantras manual manually manuals manufacture manufactured manufacturer manufacturer's manufacturers manufactures manufacturing manure manure's manured manures manuring manuscript manuscript's manuscripts many map map's maple maple's maples mapped mapper mapping mapping's mappings maps mar marathon marathon's marathons marble marble's marbled marbles marbling march marched marcher marcher's marches marching mare mare's mares margarine margarine's margin margin's marginal marginally marginals margins marigold marigold's marigolds marijuana marijuana's marina marina's marinade marinade's marinaded marinades marinading marinas marinate marinated marinates marinating marine mariner mariner's mariners marines marionette marionette's marionettes marital maritime mark mark's markdown markdown's markdowns marked markedly marker marker's markers market market's marketability marketability's marketable marketed marketer marketer's marketers marketing marketing's marketplace marketplace's marketplaces markets marking marking's markings marks marksman marksman's marksmen markup markup's markups marmalade marmalade's maroon marooned marooning maroons marquee marquee's marquees marred marriage marriage's marriages married marrieds marries marring marrow marrow's marrowed marrowing marrows marry marrying mars marsh marsh's marshal marshal's marshaled marshaling marshalled marshalling marshals marshes marshier marshiest marshmallow marshmallow's marshmallows marshy marsupial marsupial's marsupials mart mart's marted martial martin martin's marting marts martyr martyr's martyrdom martyrdom's martyred martyring martyrs marvel marvelled marvelling marvellous marvels mas mascara mascara's mascaraed mascaraing mascaras mascot mascot's mascots masculine masculines masculinity masculinity's mash mash's mashed mashes mashing mask mask's masked masking masks masochism masochism's masochist masochist's masochistic masochists mason mason's masonry masonry's masons masquerade masquerade's masqueraded masquerades masquerading mass massacre massacre's massacred massacres massacring massage massage's massaged massages massaging massed masses masseur masseur's masseurs masseuse masseuse's masseuses massing massive massively mast mast's master master's mastered masterful mastering masterly mastermind masterminded masterminding masterminds masterpiece masterpiece's masterpieces masters mastery mastery's masticate masticated masticates masticating masts masturbate masturbated masturbates masturbating masturbation masturbation's mat mat's matador matador's matadors match match's matchbook matchbook's matchbooks matchbox matchbox's matchboxes matched matches matching matchless matchmaker matchmaker's matchmakers matchmaking matchmaking's matchstick matchstick's matchsticks mate mate's mated material material's materialise materialised materialises materialising materialism materialism's materialist materialist's materialistic materialists materials maternal maternity maternity's mates math math's mathematical mathematically mathematician mathematician's mathematicians mathematics mathematics's mating mating's matine matines matriarch matriarch's matriarchal matriarchies matriarchs matriarchy matriarchy's matrices matriculate matriculated matriculates matriculating matriculation matriculation's matrimonial matrimony matrimony's matrix matrix's matrixes matron matron's matronly matrons mats matt matte matte's matted matter matter's mattered mattering matters mattes matting matting's mattress mattress's mattresses matts mature matured maturer matures maturest maturing maturities maturity maturity's maudlin maul mauled mauling mauls mausolea mausoleum mausoleum's mausoleums mauve mauve's maverick maverick's mavericked mavericking mavericks mawkish maxed maxes maxim maxim's maxima maxima's maximal maximise maximised maximises maximising maxims maximum maximum's maximums maxing may maybe maybes mayday maydays mayhem mayhem's mayo mayonnaise mayonnaise's mayor mayor's mayors maze maze's mazes me meadow meadow's meadows meagre meal meal's mealed mealier mealies mealiest mealing meals mealtime mealtime's mealtimes mealy mean meander meandered meandering meanders meaner meanest meaning meaning's meaningful meaningfully meaningless meanings means means's meant meantime meantime's meanwhile measles measles's measlier measliest measly measurable measure measure's measured measurement measurement's measurements measures measuring meat meat's meatball meatball's meatballs meatier meatiest meatloaf meatloaves meats meaty mecca meccas mechanic mechanic's mechanical mechanically mechanics mechanisation mechanisation's mechanise mechanised mechanises mechanising mechanism mechanism's mechanisms medal medal's medallion medallion's medallions medallist medallists medals meddle meddled meddler meddlers meddles meddlesome meddling media media's mediaeval median medians medias mediate mediated mediates mediating mediation mediation's mediator mediator's mediators medical medically medicals medicate medicated medicates medicating medication medication's medications medicinal medicinals medicine medicine's medicines medieval mediocre mediocrities mediocrity mediocrity's meditate meditated meditates meditating meditation meditation's meditations medium mediums medley medley's medleys meek meeker meekest meekly meekness meekness's meet meeter meeting meeting's meetinghouse meetinghouses meetings meets meg meg's megabyte megabytes megalomania megalomania's megalomaniac megalomaniac's megalomaniacs megaphone megaphone's megaphoned megaphones megaphoning megaton megaton's megatons megs melancholy melancholy's meld melded melding melds mellow mellowed mellower mellowest mellowing mellows melodic melodics melodies melodious melodrama melodrama's melodramas melodramatic melodramatics melody melody's melon melon's melons melt meltdown meltdowns melted melting melts member member's members membership membership's memberships membrane membrane's membranes memento memento's mementoes mementos memo memo's memoir memoirs memorabilia memorable memorably memoranda memorandum memorandum's memorandums memorial memorials memories memorise memorised memorises memorising memory memory's memos men men's menace menaced menaces menacing menagerie menagerie's menageries mend mended mending mending's mends menial menials meningitis meningitis's menopause menopause's menorah menorah's menorahs menstrual menstruate menstruated menstruates menstruating menstruation menstruation's mental mentalities mentality mentality's mentally menthol menthol's mention mentioned mentioning mentions mentor mentor's mentored mentoring mentors menu menu's menus meow meowed meowing meows mercantile mercenaries mercenary merchandise merchandise's merchandised merchandises merchandising merchant merchant's merchanted merchanting merchants mercies merciful mercifully merciless mercilessly mercury mercury's mercy mercy's mere mered merely merer meres merest merge merged merger merger's mergers merges merging meridian meridian's meridians mering meringue meringue's meringues merit merit's merited meriting merits mermaid mermaid's mermaids merrier merriest merrily merriment merriment's merry mes mesdames mesh mesh's meshed meshes meshing mesmerise mesmerised mesmerises mesmerising mess mess's message message's messaged messages messaging messed messenger messenger's messengers messes messier messiest messing messy met metabolic metabolism metabolism's metabolisms metal metal's metallic metallurgist metallurgists metallurgy metallurgy's metals metamorphose metamorphoses metamorphosis metamorphosis's metaphor metaphor's metaphorical metaphorically metaphors metaphysical metaphysics mete meted meteor meteor's meteoric meteorite meteorite's meteorites meteorological meteorologist meteorologists meteorology meteorology's meteors meter meter's metered metering meters metes methadone methadone's methane methane's method method's methodical methodically methodological methodologies methodology methodology's methods meticulous meticulously meting metre metre's metred metres metric metring metro metro's metropolis metropolis's metropolises metropolitan metros mettle mettle's mew mewed mewing mews mezzanine mezzanine's mezzanines mi mi's miaow miaowed miaowing miaows mice mice's microbe microbe's microbes microbiology microbiology's microchip microchips microcode microcomputer microcomputers microcosm microcosm's microcosms microfiche microfiche's microfiches microfilm microfilm's microfilmed microfilming microfilms micrometre micrometre's micrometres microorganism microorganism's microorganisms microphone microphone's microphones microprocessor microprocessor's microprocessors microscope microscope's microscopes microscopic microsecond microseconds microwave microwave's microwaved microwaves microwaving midair midair's midday midday's middle middleman middleman's middlemen middles midget midget's midgets midnight midnight's midriff midriff's midriffs midst midst's midstream midstream's midsummer midsummer's midterm midterm's midterms midway midways midweek midweek's midweeks midwife midwife's midwifed midwifes midwifing midwinter midwinter's midwived midwives midwiving mien mien's miens miff miffed miffing miffs might mightier mightiest mighty migraine migraine's migraines migrant migrant's migrants migrate migrated migrates migrating migration migration's migrations migratory mike mike's miked mikes miking mild milder mildest mildew mildew's mildewed mildewing mildews mildly mildness mildness's mile mile's mileage mileage's mileages miles milestone milestone's milestones milieu milieu's milieus milieux militancy militancy's militant militants militaries militarily militarism militarism's military militate militated militates militating militia militia's militias milk milk's milked milker milkier milkiest milking milkman milkman's milkmen milks milky mill mill's milled millennia millennium millennium's millenniums miller miller's millers milligramme milligramme's milligrammes millilitre millilitre's millilitres millimetre millimetre's millimetres milliner milliner's milliners millinery millinery's milling milling's million million's millionaire millionaire's millionaires millions millionth millionth's millionths millisecond milliseconds mills mime mime's mimed mimes mimic mimicked mimicking mimicries mimicry mimicry's mimics miming mince minced mincemeat mincemeat's minces mincing mind mind's mindbogglingly minded mindedness mindful minding mindless mindlessly minds mine mined minefield minefield's minefields miner miner's mineral mineral's minerals miners mines mingle mingled mingles mingling mini miniature miniature's miniatured miniatures miniaturing minibus minibus's minibuses minibusses minicomputer minicomputer's minima minimal minimalism minimalist minimalist's minimally minimals minimise minimised minimises minimising minimum minimum's minimums mining mining's minion minion's minions minis miniseries miniskirt miniskirt's miniskirts minister minister's ministered ministerial ministering ministers ministries ministry ministry's minivan minivans mink mink's minks minnow minnow's minnows minor minored minoring minorities minority minority's minors minstrel minstrel's minstrels mint mint's minted mintier mintiest minting mints minty minuet minuet's minuets minus minuscule minuscule's minuscules minuses minute minute's minuted minuter minutes minutest minuting miracle miracle's miracles miraculous miraculously mirage mirage's mirages mire mire's mired mires miring mirror mirror's mirrored mirroring mirrors mirth mirth's misadventure misadventure's misadventures misapprehension misapprehension's misappropriate misappropriated misappropriates misappropriating misappropriation misappropriations misbehave misbehaved misbehaves misbehaving misbehaviour misbehaviour's miscalculate miscalculated miscalculates miscalculating miscalculation miscalculation's miscalculations miscarriage miscarriage's miscarriages miscarried miscarries miscarry miscarrying miscellaneous miscellany miscellany's mischief mischief's mischiefed mischiefing mischiefs mischievous mischievously misconception misconception's misconceptions misconduct misconduct's misconducted misconducting misconducts misconstrue misconstrued misconstrues misconstruing misdeed misdeed's misdeeds misdemeanour misdemeanour's misdemeanours misdirect misdirected misdirecting misdirection misdirection's misdirects miser miser's miserable miserables miserably miseries miserly misers misery misery's misfit misfit's misfits misfitted misfitting misfortune misfortune's misfortunes misgiving misgiving's misgivings misguide misguided misguides misguiding mishap mishap's mishapped mishapping mishaps misinform misinformation misinformation's misinformed misinforming misinforms misinterpret misinterpretation misinterpretation's misinterpretations misinterpreted misinterpreting misinterprets misjudge misjudged misjudgement misjudgements misjudges misjudging mislaid mislay mislaying mislays mislead misleading misleads misled mismanage mismanaged mismanagement mismanagement's mismanages mismanaging mismatch mismatched mismatches mismatching misnomer misnomer's misnomered misnomering misnomers misogynist misogynist's misogynists misogyny misogyny's misplace misplaced misplaces misplacing misprint misprint's misprinted misprinting misprints mispronounce mispronounced mispronounces mispronouncing mispronunciation mispronunciation's mispronunciations misquote misquoted misquotes misquoting misread misreading misreadings misreads misrepresent misrepresentation misrepresentation's misrepresentations misrepresented misrepresenting misrepresents miss missed misses misshapen missile missile's missiles missing mission mission's missionaries missionary missionary's missioned missioning missions missive missive's missives misspell misspelled misspelling misspelling's misspellings misspells misspelt misspend misspending misspends misspent misstep misstep's misstepped misstepping missteps mist mist's mistake mistake's mistaken mistakenly mistakes mistaking misted mister mister's misters mistier mistiest misting mistletoe mistletoe's mistook mistreat mistreated mistreating mistreatment mistreatment's mistreats mistress mistress's mistresses mistrial mistrial's mistrials mistrust mistrusted mistrusting mistrusts mists misty mistype mistyping misunderstand misunderstanding misunderstanding's misunderstandings misunderstands misunderstood misuse misuse's misused misuses misusing mite mite's mites mitigate mitigated mitigates mitigating mitigation mitigation's mitt mitt's mitten mitten's mittens mitts mix mixed mixer mixer's mixers mixes mixing mixt mixture mixture's mixtures mnemonic mnemonics mnemonics's moan moan's moaned moaning moans moat moat's moated moating moats mob mob's mobbed mobbing mobile mobiles mobilisation mobilisation's mobilisations mobilise mobilised mobilises mobilising mobility mobility's mobs moccasin moccasin's moccasins mock mocked mockeries mockery mockery's mocking mockingbird mockingbird's mockingbirds mocks mod modal modals mode mode's model model's modelled modelling modelling's modellings models modem modem's modems moder moderate moderated moderately moderates moderating moderation moderation's moderator moderator's moderators modern moderner modernest modernisation modernisation's modernise modernised modernises modernising modernity modernity's moderns modes modest modester modestest modestly modesty modesty's modicum modicum's modicums modification modification's modifications modified modifier modifier's modifiers modifies modify modifying modular modulate modulated modulates modulating modulation modulation's modulations module module's modules mohair mohair's moist moisten moistened moistening moistens moister moistest moisture moisture's moisturiser moisturisers molar molar's molars molasses molasses's mold mold's molded molding molding's moldings molds mole mole's molecular molecule molecule's molecules moles molest molestation molestation's molested molester molester's molesters molesting molests mollified mollifies mollify mollifying mollusk mollusks molt molted molten molting molts mom mom's moment moment's momentarily momentary momentous moments momentum momentum's momma mommas mommie mommies mommy mommy's moms monarch monarch's monarchies monarchs monarchy monarchy's monasteries monastery monastery's monastic monastics monetarism monetary money money's mongoose mongoose's mongrel mongrel's mongrels monies monies's moniker moniker's monikers monitor monitor's monitored monitoring monitors monk monk's monkey monkey's monkeyed monkeying monkeys monks mono monochrome monochrome's monochromes monogamous monogamy monogamy's monogram monogram's monogramed monograming monogrammed monogramming monograms monolingual monolinguals monolith monolith's monolithic monoliths monologue monologue's monologued monologues monologuing mononucleosis mononucleosis's monopolies monopolisation monopolise monopolised monopolises monopolising monopoly monopoly's monorail monorail's monorails monosyllable monosyllable's monosyllables monotone monotone's monotoned monotones monotonically monotoning monotonous monotonously monotony monotony's monsoon monsoon's monsoons monster monster's monsters monstrosities monstrosity monstrosity's monstrous montage montage's montages month month's monthlies monthly months monument monument's monumental monuments moo mooch mooched mooches mooching mood mood's moodier moodiest moodily moodiness moodiness's moods moody mooed mooing moon moon's moonbeam moonbeam's moonbeams mooned mooning moonlight moonlight's moonlighted moonlighting moonlighting's moonlights moonlit moons moor moor's moored mooring mooring's moorings moors moos moose moose's moot mooted mooter mooting moots mop mop's mope moped moped's mopeds mopes moping mopped mopping mops moral morale morale's moralist moralist's moralistic moralists moralities morality morality's moralled moralling morally morals morass morass's morasses moratoria moratorium moratorium's moratoriums morbid more moreover mores morgue morgue's morgues morn morn's morned morning morning's mornings morns moron moron's moronic morons morose morphine morphine's morphology morphology's morsel morsel's morsels mortal mortality mortality's mortally mortals mortar mortar's mortarboard mortarboard's mortarboards mortared mortaring mortars mortgage mortgage's mortgaged mortgages mortgaging mortician mortician's morticians mortification mortification's mortified mortifies mortify mortifying mortuaries mortuary mortuary's mosaic mosaic's mosaics moses mosque mosque's mosques mosquito mosquito's mosquitoes mosquitos moss moss's mossed mosses mossier mossies mossiest mossing mossy most mostly motel motel's motels moth moth's mothball mothball's mothballed mothballing mothballs mother mother's motherboard motherboards mothered motherfucker motherfucker's motherfuckers motherhood motherhood's mothering motherly mothers moths motif motif's motifs motion motion's motioned motioning motionless motions motivate motivated motivates motivating motivation motivation's motivations motive motive's motives motley motleyer motleyest motleys motlier motliest motor motor's motorbike motorbike's motorbiked motorbikes motorbiking motorboat motorboat's motorboats motorcade motorcade's motorcades motorcycle motorcycle's motorcycled motorcycles motorcycling motorcyclist motorcyclist's motorcyclists motored motoring motoring's motorise motorised motorises motorising motorist motorist's motorists motormouth motormouths motors motorway motorway's motorways mottle mottled mottles mottling motto motto's mottoes mottos mould mould's moulded mouldier mouldiest moulding moulding's mouldings moulds mouldy mound mound's mounded mounding mounds mount mountain mountain's mountaineer mountaineer's mountaineered mountaineering mountaineering's mountaineers mountainous mountains mountainside mountainside's mountainsides mounted mounting mounting's mountings mounts mourn mourned mourner mourner's mourners mournful mournfuller mournfullest mournfully mourning mourning's mourns mouse mouse's moused mouses mousey mousier mousiest mousing mousse mousse's moussed mousses moussing moustache moustache's moustaches mousy mouth mouth's mouthed mouthful mouthful's mouthfuls mouthing mouthpiece mouthpiece's mouthpieces mouths mouthwash mouthwash's mouthwashes movable movables move moved movement movement's movements mover mover's movers moves movie movie's movies moving mow mowed mower mower's mowers mowing mown mows ms mu mu's much muck muck's mucked mucking mucks mucous mucus mucus's mud mud's muddied muddier muddies muddiest muddle muddled muddles muddling muddy muddying mudslide mudslides mudslinging mudslinging's muff muff's muffed muffin muffin's muffing muffins muffle muffled muffler muffler's mufflers muffles muffling muffs mug mug's mugged mugger mugger's muggers muggier muggiest mugginess mugging muggings muggy mugs mulatto mulatto's mulattoes mulattos mulch mulch's mulched mulches mulching mule mule's muled mules muling mull mulled mulling mulls multicultural multilateral multimedia multimillionaire multimillionaire's multimillionaires multinational multinationals multiple multiples multiplex multiplex's multiplexed multiplexes multiplexing multiplication multiplication's multiplications multiplicative multiplicities multiplicity multiplicity's multiplied multiplies multiply multiplying multiprocessing multitasking multitude multitude's multitudes mum mum's mumble mumbled mumbles mumbling mummies mummified mummifies mummify mummifying mummy mummy's mumps mumps's mums munch munched munches munchies munching mundane mundanes municipal municipalities municipality municipality's municipals munition munitions mural mural's murals murder murder's murdered murderer murderer's murderers murdering murderous murders murkier murkiest murky murmur murmur's murmured murmuring murmurs muscle muscle's muscled muscles muscling muscular muse mused muses museum museum's museums mush mush's mushed mushes mushier mushiest mushing mushroom mushroom's mushroomed mushrooming mushrooms mushy music music's musical musically musicals musician musician's musicians musicked musicking musics musing musings musk musk's musked musket musket's muskets musking musks muss mussed mussel mussel's mussels musses mussing must mustang mustang's mustangs mustard mustard's muster mustered mustering musters mustier mustiest mustn't musts musty mutability mutability's mutable mutant mutant's mutants mutate mutated mutates mutating mutation mutation's mutations mute muted mutely muter mutes mutest mutilate mutilated mutilates mutilating mutilation mutilation's mutilations muting mutinied mutinies mutinous mutiny mutiny's mutinying mutt mutt's mutter muttered muttering mutters mutton mutton's mutts mutual mutually muzzle muzzle's muzzled muzzles muzzling my myopic myopics myriad myriads mys myself mysteried mysteries mysterious mysteriously mystery mystery's mysterying mystic mystic's mystical mysticism mysticism's mystics mystified mystifies mystify mystifying mystique mystique's myth myth's mythical mythological mythologies mythology mythology's myths mle mle's mles n nab nabbed nabbing nabs nag nagged nagging nags nail nail's nailbrush nailbrush's nailbrushes nailed nailing nails naive naively naiver naives naivest naivety naivety's naivet naivet's naked nakeder nakedest nakedness nakedness's name name's named named's nameless namely names namesake namesake's namesakes naming naming's nannied nannies nanny nanny's nannying nap napalm napalm's napalmed napalming napalms nape nape's napes napkin napkin's napkins napped nappier nappies nappiest napping nappy nappy's naps narc narced narcing narcissism narcissism's narcissist narcissist's narcissistic narcissists narcotic narcotic's narcotics narcs narrate narrated narrates narrating narration narration's narrations narrative narrative's narratives narrator narrator's narrators narrow narrowed narrower narrowest narrowing narrowly narrowness narrowness's narrows nasal nasally nasals nastier nastiest nastily nastiness nastiness's nasty nation nation's national nationalisation nationalisation's nationalisations nationalise nationalised nationalises nationalising nationalism nationalism's nationalist nationalist's nationalistic nationalists nationalities nationality nationality's nationally nationals nations nationwide native natives nativities nativity nativity's nattier nattiest natty natural naturalisation naturalisation's naturalise naturalised naturalises naturalising naturalist naturalist's naturalists naturally naturalness naturals nature nature's natured natures naturing naughtier naughties naughtiest naughtily naughtiness naughtiness's naughty nausea nausea's nauseate nauseated nauseates nauseating nauseous nautical naval navel navel's navels navies navigable navigate navigated navigates navigating navigation navigation's navigational navigator navigator's navigators navy navy's nay nay's nays near nearby neared nearer nearest nearing nearlier nearliest nearly nears nearsighted nearsightedness neat neater neatest neatly neatness neatness's nebula nebula's nebulae nebulas nebulous necessaries necessarily necessary necessitate necessitated necessitates necessitating necessities necessity necessity's neck neck's necked neckerchief neckerchief's neckerchiefs neckerchieves necking necklace necklace's necklaces neckline neckline's necklines necks necktie necktie's neckties necrophilia necrophilia's nectar nectar's nectarine nectarine's nectarines need needed needier neediest needing needle needle's needled needles needless needlessly needlework needlework's needling needs needy negate negated negates negating negation negation's negations negative negatived negatively negatives negativing neglect neglected neglectful neglecting neglects negligee negligee's negligees negligence negligence's negligent negligently negligible negotiable negotiate negotiated negotiates negotiating negotiation negotiation's negotiations negotiator negotiator's negotiators negs neigh neigh's neighbour neighbour's neighboured neighbourhood neighbourhood's neighbourhoods neighbouring neighbourliness neighbourliness's neighbourly neighbours neighed neighing neighs neither neon neon's neophyte neophyte's neophytes nephew nephew's nephews nepotism nepotism's nerd nerdier nerdiest nerds nerdy nerve nerve's nerved nerves nerving nervous nervously nervousness nervousness's nest nest's nested nesting nestle nestled nestles nestling nests net net's nether nets netted netting netting's nettle nettle's nettled nettles nettling network network's networked networking networks neural neurological neurologist neurologist's neurologists neurology neurology's neuron neuron's neurons neuroses neurosis neurosis's neurotic neurotics neuter neutered neutering neuters neutral neutralisation neutralisation's neutralise neutralised neutralises neutralising neutrality neutrality's neutrals neutron neutron's neutrons never nevertheless new newbie newbies newborn newborns newcomer newcomer's newcomers newed newer newest newfangled newing newly newlywed newlywed's newlyweds newness newness's news news's newsagents newscast newscast's newscaster newscaster's newscasters newscasting newscasts newsed newses newsier newsiest newsing newsletter newsletter's newsletters newspaper newspaper's newspapered newspapering newspapers newsprint newsprint's newsstand newsstand's newsstands newsworthier newsworthiest newsworthy newsy newt newt's newton newton's newts next nibble nibbled nibbles nibbling nice nicely nicer nicest niceties nicety niche niche's niches nick nick's nicked nickel nickel's nickels nicking nickname nickname's nicknamed nicknames nicknaming nicks nicotine nicotine's niece niece's nieces niftier niftiest nifty nigger nigger's niggers niggle niggled niggles niggling nigglings nigh night night's nightclub nightclub's nightclubbed nightclubbing nightclubs nightfall nightfall's nightgown nightgown's nightgowns nightie nightie's nighties nightingale nightingale's nightingales nightlife nightlife's nightly nightmare nightmare's nightmares nightmarish nights nighttime nighty nil nil's nilled nilling nils nimble nimbler nimblest nimbly nincompoop nincompoop's nincompoops nine nine's nines nineteen nineteen's nineteens nineteenth nineteenths nineties ninetieth ninetieths ninety ninety's ninnies ninny ninny's ninth ninths nip nipped nippier nippiest nipping nipple nipple's nippled nipples nippling nippy nips nit nit's nitrate nitrate's nitrated nitrates nitrating nitrogen nitrogen's nits nitwit nitwit's nitwits no nobility nobility's noble nobleman nobleman's noblemen nobler nobles noblest noblewoman noblewomen nobly nobodies nobody nocturnal nod nodded nodding node node's nodes nods noes noise noise's noised noiseless noiselessly noises noisier noisiest noisily noisiness noisiness's noising noisy nomad nomad's nomadic nomads nomenclature nomenclature's nomenclatures nominal nominally nominate nominated nominates nominating nomination nomination's nominations nominative nominatives nominee nominee's nominees non nonchalance nonchalance's nonchalant nonchalantly noncommittal noncommittally nonconformist nonconformist's nonconformists nondairy nondenominational nondescript none nonentities nonentity nonentity's nones nonetheless nonevent nonevent's nonevents nonexistent nonfat nonfiction nonfiction's nonflammable nonintervention nonintervention's nonpartisan nonpartisans nonplus nonplused nonpluses nonplusing nonplussed nonplusses nonplussing nonprofit nonprofits nonproliferation nonproliferation's nonrefundable nonrenewable nonresident nonresident's nonresidents nonsense nonsense's nonsensical nonsmoker nonsmoker's nonsmokers nonsmoking nonstandard nonstick nonstop nontrivial nonverbal nonviolence nonviolence's nonviolent noodle noodle's noodled noodles noodling nook nook's nooks noon noon's nooned nooning noons noose noose's nooses nope nopes nor norm norm's normal normalcy normalcy's normalisation normalise normalised normalises normalising normality normality's normally normed norming norms north north's northbound northeast northeast's northeasterly northeastern northeastward northerlies northerly northern northerner northerners northernmost northward northwest northwest's northwesterly northwestern northwestward nose nose's nosebleed nosebleed's nosebleeds nosed nosedive nosedived nosedives nosediving nosedove noses nosey nosey's noseyer noseyest noseys nosing nostalgia nostalgia's nostalgic nostalgically nostalgics nostril nostril's nostrils not notable notables notably notation notation's notations notch notch's notched notches notching note note's notebook notebook's notebooks noted notes noteworthy nothing nothingness nothingness's nothings notice notice's noticeable noticeably noticeboard noticeboards noticed notices noticing notification notification's notifications notified notifies notify notifying noting notion notion's notional notions notoriety notorious notoriously notwithstanding nougat nougat's nougats nought nought's noughts noun noun's nouns nourish nourished nourishes nourishing nourishment nourishment's nova nova's novel novel's novelist novelist's novelists novels novelties novelty novelty's novice novice's novices now nowadays nowhere noxious nozzle nozzle's nozzles nuance nuance's nuances nuclear nuclei nuclei's nucleus nucleus's nucleuses nude nuder nudes nudest nudge nudged nudges nudging nudist nudist's nudists nudity nudity's nugget nugget's nuggets nuisance nuisance's nuisances nuke nuke's nuked nukes nuking null nullified nullifies nullify nullifying nulls numb numbed number number's numbered numbering numbers numbest numbing numbness numbness's numbs numeral numeral's numerals numerate numerator numerator's numerators numeric numerical numerically numerous nun nun's nuns nuptial nuptials nurse nurse's nursed nursemaid nursemaid's nursemaids nurseries nursery nursery's nurses nursing nurture nurture's nurtured nurtures nurturing nut nut's nutcracker nutcracker's nutcrackers nutmeg nutmeg's nutmegged nutmegging nutmegs nutrient nutrient's nutrients nutriment nutriment's nutriments nutrition nutrition's nutritional nutritious nuts nutshell nutshell's nutshells nutted nuttier nuttiest nutting nutty nuzzle nuzzled nuzzles nuzzling nylon nylon's nylons nymph nymph's nymphomania nymphomania's nymphomaniac nymphomaniacs nymphs ne o o'clock oaf oaf's oafs oak oak's oaks oar oar's oared oaring oars oases oasis oasis's oat oat's oath oath's oaths oatmeal oatmeal's oats obedience obedience's obedient obediently obelisk obelisk's obelisks obese obesity obesity's obey obeyed obeying obeys obfuscation obfuscation's obituaries obituary obituary's object object's objected objecting objection objection's objectionable objections objective objectively objectives objectivity objectivity's objector objector's objectors objects obligate obligated obligates obligating obligation obligation's obligations obligatory oblige obliged obliges obliging obligingly oblique obliques obliterate obliterated obliterates obliterating obliteration obliteration's oblivion oblivion's oblivious oblong oblongs obnoxious obnoxiously oboe oboe's oboes obscene obscener obscenest obscenities obscenity obscenity's obscure obscured obscurer obscures obscurest obscuring obscurities obscurity obscurity's observable observance observance's observances observant observation observation's observations observatories observatory observatory's observe observed observer observer's observers observes observing obsess obsessed obsesses obsessing obsession obsession's obsessions obsessive obsessively obsessives obsolescence obsolescent obsolete obsoleted obsoletes obsoleting obstacle obstacle's obstacles obstetrician obstetrician's obstetricians obstetrics obstetrics's obstinacy obstinacy's obstinate obstinately obstruct obstructed obstructing obstruction obstruction's obstructions obstructive obstructives obstructs obtain obtainable obtained obtaining obtains obtrusive obtuse obtuser obtusest obvious obviously occasion occasion's occasional occasionally occasioned occasioning occasions occult occupancy occupancy's occupant occupant's occupants occupation occupation's occupational occupations occupied occupies occupy occupying occur occurred occurrence occurrence's occurrences occurring occurs ocean ocean's oceanic oceanography oceanography's oceans octagon octagon's octagonal octagons octal octave octave's octaves octopi octopus octopus's octopuses ocular oculars odd odder oddest oddities oddity oddity's oddly oddness oddness's odds ode ode's odes odious odometer odometer's odometers odour odour's odours odyssey odysseys oesophagus oesophagus's oesophaguses oestrogen oestrogen's of off offbeat offbeat's offbeats offed offence offence's offences offencive offend offended offender offender's offenders offending offends offensively offensiveness offensiveness's offensives offer offered offering offering's offerings offers offhand office office's officer officer's officers offices official officially officials officiate officiated officiates officiating officious offing offing's offings offload offs offset offset's offsets offsetting offshoot offshoot's offshoots offshore offspring offspring's offsprings offstage offstages often oftener oftenest ogle ogled ogles ogling ogre ogre's ogres oh ohm ohm's ohms ohs oil oil's oiled oilfield oilfield's oilfields oilier oiliest oiling oils oily oink oinked oinking oinks ointment ointment's ointments okay okayed okaying okays okra okra's okras old olden oldened oldening oldens older oldest oldie oldie's oldies olfactory olive olive's olives ombudsman ombudsman's ombudsmen omega omega's omelet omelet's omelets omelette omelette's omelettes omen omen's omens ominous ominously omission omission's omissions omit omits omitted omitting omnibus omnibus's omnipotence omnipotence's omnipotent omnipresent omniscience omniscience's omniscient on once oncoming one onerous ones oneself onetime ongoing ongoings onion onion's onioned onioning onions onliest onlooker onlooker's onlookers only onomatopoeia onomatopoeia's onrush onrush's onrushes onset onset's onsets onsetting onslaught onslaught's onslaughts onto onus onus's onuses onward onwards oodles oops oopses ooze oozed oozes oozing opal opal's opals opaque opaqued opaquer opaques opaquest opaquing open opened opener opener's openers openest opening opening's openings openly openness opens opera opera's operable operand operand's operands operas operate operated operates operatic operatics operating operation operation's operational operationally operations operative operatives operator operator's operators ophthalmologist ophthalmologist's ophthalmologists ophthalmology ophthalmology's opinion opinion's opinionated opinions opium opium's opossum opossum's opossums opponent opponent's opponents opportune opportunism opportunism's opportunist opportunist's opportunistic opportunists opportunities opportunity opportunity's oppose opposed opposes opposing opposite opposites opposition opposition's oppress oppressed oppresses oppressing oppression oppression's oppressive oppressor oppressor's oppressors opt opted optic optical optician optician's opticians optics optics's optima optimal optimisation optimisation's optimise optimise's optimised optimises optimising optimism optimism's optimist optimist's optimistic optimistically optimists optimum optimum's optimums opting option option's optional optionally optionals optioned optioning options optometrist optometrist's optometrists optometry optometry's opts opulence opulence's opulent opus opus's opuses or or's oracle oracle's oracled oracles oracling oral orally orals orange orange's oranges orangutan orangutan's orangutans oration oration's orations orator orator's oratories orators oratory oratory's orbit orbit's orbital orbital's orbitals orbited orbiting orbits orchard orchard's orchards orchestra orchestra's orchestral orchestras orchestrate orchestrated orchestrates orchestrating orchestration orchestration's orchestrations orchid orchid's orchids ordain ordained ordaining ordains ordeal ordeal's ordeals order order's ordered ordering orderlies orderly orders ordinal ordinals ordinance ordinance's ordinances ordinarier ordinaries ordinariest ordinarily ordinary ordination ordination's ordinations ore ore's ores organ organ's organic organically organics organisation organisation's organisational organisations organise organised organiser organiser's organisers organises organising organism organism's organisms organist organist's organists organs orgasm orgasm's orgasms orgies orgy orgy's orient orient's oriental orientals orientate orientated orientates orientating orientation orientation's orientations oriented orienting orients orifice orifice's origin origin's original originality originality's originally originals originate originated originates originating originator originator's originators origins oriole oriole's orioles ornament ornament's ornamental ornamented ornamenting ornaments ornate ornately ornithologist ornithologist's ornithologists ornithology ornithology's orphan orphan's orphanage orphanage's orphanages orphaned orphaning orphans orthodontics orthodontics's orthodontist orthodontist's orthodontists orthodox orthodoxes orthodoxies orthodoxy orthodoxy's orthogonal orthogonality orthogonality's orthography orthography's orthopaedics orthopaedics's oscillate oscillated oscillates oscillating oscillation oscillations oscilloscope oscilloscope's osmosis osmosis's ostensible ostensibly ostentation ostentation's ostentatious ostentatiously ostracise ostracised ostracises ostracising ostracism ostracism's ostrich ostrich's ostriches other others otherwise otter otter's ottered ottering otters ouch ought ounce ounce's ounces our ours ourselves oust ousted ouster ouster's ousters ousting ousts out outage outage's outages outback outback's outbacks outbid outbidding outbids outbound outbreak outbreak's outbreaking outbreaks outbroke outbroken outburst outburst's outbursting outbursts outcast outcast's outcasting outcasts outclass outclassed outclasses outclassing outcome outcome's outcomes outcries outcrop outcropped outcropping outcroppings outcrops outcry outcry's outdated outdid outdistance outdistanced outdistances outdistancing outdo outdoes outdoing outdone outdoor outdoors outed outer outermost outers outfield outfield's outfielder outfielder's outfielders outfields outfit outfit's outfits outfitted outfitting outgoing outgoings outgrew outgrow outgrowing outgrown outgrows outgrowth outgrowth's outgrowths outhouse outhouse's outhouses outing outing's outings outlaid outlandish outlast outlasted outlasting outlasts outlaw outlaw's outlawed outlawing outlaws outlay outlay's outlaying outlays outlet outlet's outlets outline outline's outlined outlines outlining outlive outlived outlives outliving outlook outlook's outlooked outlooking outlooks outlying outmanoeuvre outmanoeuvred outmanoeuvres outmanoeuvring outmoded outnumber outnumbered outnumbering outnumbers outpatient outpatient's outpatients outperform outperformed outperforming outperforms outplacement outpost outpost's outposts outpouring outpouring's outpourings output output's outputs outputted outputting outrage outrage's outraged outrageous outrageously outrages outraging outran outreach outreached outreaches outreaching outright outrun outrunning outruns outs outset outset's outsets outsetting outshine outshined outshines outshining outshone outside outsider outsider's outsiders outsides outskirt outskirts outsmart outsmarted outsmarting outsmarts outsource outsourced outsources outsourcing outspoken outspokenness outspokenness's outstanding outstandingly outstation outstation's outstations outstretch outstretched outstretches outstretching outstrip outstripped outstripping outstrips outstript outward outwardly outwards outweigh outweighed outweighing outweighs outwit outwits outwitted outwitting ova ova's oval ovals ovarian ovaries ovary ovary's ovation ovation's ovations oven oven's ovens over overall overalls overate overbear overbearing overbears overblown overboard overbore overborne overburden overburdened overburdening overburdens overcame overcast overcasting overcasts overcharge overcharged overcharges overcharging overcoat overcoat's overcoats overcome overcomes overcoming overcompensate overcompensated overcompensates overcompensating overcompensation overcompensation's overcrowd overcrowded overcrowding overcrowds overdid overdo overdoes overdoing overdone overdose overdose's overdosed overdoses overdosing overdraft overdraft's overdraw overdrawing overdrawn overdraws overdrew overdue overeat overeaten overeating overeats overestimate overestimated overestimates overestimating overextend overextended overextending overextends overflow overflowed overflowing overflows overgrew overgrow overgrowing overgrown overgrows overhand overhands overhang overhanging overhangs overhaul overhauled overhauling overhauls overhead overheads overhear overheard overhearing overhears overheat overheated overheating overheats overhung overjoy overjoyed overjoying overjoys overkill overkill's overlaid overlain overland overlands overlap overlapped overlapping overlaps overlay overlaying overlays overlie overlies overload overloaded overloading overloads overlong overlook overlooked overlooking overlooks overly overlying overnight overnights overpass overpass's overpasses overpopulate overpopulated overpopulates overpopulating overpopulation overpopulation's overpower overpowered overpowering overpowers overprice overpriced overprices overpricing overprint overprinted overprinting overprints overran overrate overrated overrates overrating overreact overreacted overreacting overreacts overridden override overrides overriding overrode overrule overruled overrules overruling overrun overrunning overruns overs oversampling oversaw overseas oversee overseeing overseen overseer overseer's overseers oversees overshadow overshadowed overshadowing overshadows overshoot overshooting overshoots overshot oversight oversight's oversights oversimplification oversimplification's oversimplifications oversimplified oversimplifies oversimplify oversimplifying oversized oversleep oversleeping oversleeps overslept overstate overstated overstates overstating overstep overstepped overstepping oversteps overt overtake overtaken overtakes overtaking overthrew overthrow overthrowing overthrown overthrows overtime overtime's overtimes overtly overtone overtone's overtones overtook overture overture's overtures overturn overturned overturning overturns overuse overused overuses overusing overview overview's overviews overweight overwhelm overwhelmed overwhelming overwhelmingly overwhelms overwork overworked overworking overworks overwrite overwrites overwriting overwritten overwrought ovum ovum's ow owe owed owes owing owl owl's owls own owned owner owner's owners ownership ownership's owning owns ox ox's oxen oxen's oxes oxidation oxidation's oxide oxide's oxides oxidise oxidised oxidises oxidising oxygen oxygen's oyster oyster's oysters ozone ozone's p pa pa's pace pace's paced pacemaker pacemaker's pacemakers paces pacesetter pacesetter's pacesetters pacific pacified pacifier pacifier's pacifiers pacifies pacifism pacifism's pacifist pacifist's pacifists pacify pacifying pacing pack pack's package package's packaged packages packaging packaging's packed packer packer's packers packet packet's packets packing packing's packs pact pact's pacts pad pad's padded paddies padding padding's paddle paddle's paddled paddles paddling paddock paddock's paddocked paddocking paddocks paddy paddy's padlock padlock's padlocked padlocking padlocks padre padre's padres pads paediatrician pagan pagan's pagans page page's pageant pageant's pageantry pageantry's pageants paged pager pager's pagers pages pagination paging pagoda pagoda's pagodas paid pail pail's pails pain pain's pained painful painfuller painfullest painfully paining painkiller painkiller's painkillers painless painlessly pains painstaking painstakingly paint paint's paintbrush paintbrush's paintbrushes painted painter painter's painters painting painting's paintings paints pair pair's paired pairing pairs pal pal's palace palace's palaces palatable palate palate's palates palatial pale paled paleontologist paleontologists paleontology paleontology's paler pales palest palette palette's palettes paling pall pall's pallbearer pallbearer's pallbearers palled pallid palling pallor pallor's palls palm palm's palmed palming palms palomino palomino's palominos palpable palpably pals paltrier paltriest paltry pamper pampered pampering pampers pamphlet pamphlet's pamphlets pan panacea panacea's panaceas panache panache's pancake pancake's pancaked pancakes pancaking pancreas pancreas's pancreases pancreatic panda panda's pandas pandemonium pandemonium's pander pandered pandering panders pane pane's panel panel's panelist panelist's panelists panelled panelling panelling's panellings panels panes pang pang's panged panging pangs panhandle panhandle's panhandled panhandler panhandlers panhandles panhandling panic panic's panicked panickier panickiest panicking panicky panics panned panning panorama panorama's panoramas panoramic pans pansies pansy pansy's pant panted pantheism pantheism's panther panther's panthers pantie panties panting pantomime pantomime's pantomimed pantomimes pantomiming pantries pantry pantry's pants panty pantyhose pap pap's papa papa's papacies papacy papacy's papal papas papaya papaya's papayas paper paper's paperback paperback's paperbacked paperbacking paperbacks paperboy paperboy's paperboys papered papergirl papergirl's papergirls papering papers paperweight paperweight's paperweights paperwork paperwork's paprika paprika's papyri papyrus papyrus's papyruses par par's parable parable's parabled parables parabling parachute parachute's parachuted parachutes parachuting parade parade's paraded parades paradigm paradigm's paradigms parading paradise paradise's paradises paradox paradox's paradoxes paradoxical paradoxically paraffin paraffin's paragon paragon's paragons paragraph paragraph's paragraphed paragraphing paragraphs parakeet parakeet's parakeets paralegal paralegals parallel parallelled parallelling parallels paralyse paralysed paralyses paralysing paralysis paralysis's paralytic paralytics paramedic paramedic's paramedics parameter parameter's parameters paramilitaries paramilitary paramount paranoia paranoia's paranoid paranoids paraphernalia paraphrase paraphrase's paraphrased paraphrases paraphrasing paraplegic paraplegics parasite parasite's parasites parasitic parasol parasol's parasols paratrooper paratrooper's paratroopers parcel parcel's parcelled parcelling parcels parch parched parches parching parchment parchment's parchments pardon pardonable pardoned pardoning pardons pare pared parent parent's parentage parentage's parental parented parentheses parenthesis parenthesis's parenthesise parenthesised parenthesises parenthesising parenthetical parenthood parenthood's parenting parents pares paring parish parish's parishes parishioner parishioner's parishioners parity parity's park park's parka parka's parkas parked parking parking's parks parkway parkway's parkways parliament parliament's parliamentary parliaments parlour parlour's parlours parochial parodied parodies parody parody's parodying parole parole's paroled paroles paroling parquet parquet's parqueted parqueting parquets parred parring parrot parrot's parroted parroting parrots pars parse parsec parsecs parsed parser parser's parses parsing parsley parsley's parsnip parsnip's parsnips parson parson's parsonage parsonage's parsonages parsons part part's partake partaken partakes partaking parted partial partiality partiality's partially partials participant participant's participants participate participated participates participating participation participation's participle participle's participles particle particle's particles particular particularly particulars partied parties parting parting's partings partisan partisan's partisans partition partition's partitioned partitioning partitions partly partner partner's partnered partnering partners partnership partnership's partnerships partook partridge partridge's partridges parts partway party party's partying pas pass passable passage passage's passages passageway passageway's passageways passbook passbook's passbooks passed passenger passenger's passengers passer passerby passersby passes passing passion passion's passionate passionated passionately passionates passionating passioned passioning passions passive passively passives passport passport's passports password password's passwords pass pass's past pasta pasta's pastas paste paste's pasted pastel pastel's pastels pastes pasteurisation pasteurisation's pasteurise pasteurised pasteurises pasteurising pastiche pastiche's pastier pasties pastiest pastime pastime's pastimes pasting pastor pastor's pastoral pastorals pastors pastries pastry pastry's pasts pasture pasture's pastured pastures pasturing pasty pat patch patch's patched patches patchier patchiest patching patchwork patchwork's patchworks patchy pate pate's patent patent's patented patenting patently patents paternal paternalism paternalism's paternalistic paternity paternity's pates path path's pathetic pathetically pathological pathologically pathologist pathologists pathology pathology's pathos pathos's paths pathway pathway's pathways patience patience's patient patienter patientest patiently patients patio patio's patios patriarch patriarch's patriarchal patriarchies patriarchs patriarchy patriarchy's patricide patricide's patricides patrimonies patrimony patrimony's patriot patriot's patriotic patriotically patriotism patriotism's patriots patrol patrol's patrolled patrolling patrolman patrolman's patrolmen patrols patrolwoman patrolwomen patron patron's patronage patronage's patronages patronise patronised patronises patronising patronisingly patrons pats patted patter pattered pattering pattern pattern's patterned patterning patterns patters patties patting patty patty's paucity paucity's paunch paunch's paunched paunches paunchier paunchiest paunching paunchy pauper pauper's paupers pause paused pauses pausing pave paved pavement pavement's pavemented pavementing pavements paves pavilion pavilion's pavilions paving paving's paw paw's pawed pawing pawn pawnbroker pawnbroker's pawnbrokers pawned pawning pawns paws pay payable paycheck paycheck's paychecks payday payday's paydays payed payee payee's payees payer payers paying payload payload's payloads payment payment's payments payoff payoff's payoffs payroll payroll's payrolls pays pea pea's peace peace's peaceable peaceably peaceful peacefuller peacefullest peacefully peacefulness peacekeeping peacemaker peacemaker's peacemakers peaces peacetime peacetime's peach peach's peaches peacock peacock's peacocks peak peak's peaked peaking peaks peal peal's pealed pealing peals peanut peanut's peanuts pear pear's pearl pearl's pearled pearling pearls pears peas peasant peasant's peasants pease peat peat's pebble pebble's pebbled pebbles pebbling pecan pecan's pecans peck peck's pecked pecking pecks peculiar peculiarities peculiarity peculiarity's peculiarly pedagogical pedagogy pedagogy's pedal pedal's pedalled pedalling pedals pedant pedant's pedantic pedantically pedantry pedantry's pedants peddle peddled peddler peddler's peddlers peddles peddling pedestal pedestal's pedestals pedestrian pedestrian's pedestrians pediatrician's pediatricians pediatrics pedigree pedigree's pedigreed pedigrees pee peed peeing peek peekaboo peekaboo's peeked peeking peeks peel peeled peeling peeling's peels peep peeped peephole peephole's peepholes peeping peeps peer peer's peered peering peerless peers pees peeve peeved peeves peeving peevish peg peg's pegged pegging pegs pejorative pejoratives pelican pelican's pelicans pellet pellet's pelleted pelleting pellets pelt pelted pelting pelts pelves pelvic pelvics pelvis pelvis's pelvises pen pen's penal penalise penalised penalises penalising penalties penalty penalty's penance penance's penanced penances penancing pence pence's penchant penchant's penchants pencil pencil's pencilled pencilling pencillings pencils pendant pendant's pendants pended pending pends pendulum pendulum's pendulums penes penetrate penetrated penetrates penetrating penetration penetration's penetrations penguin penguin's penguins penicillin penicillin's peninsula peninsula's peninsulas penis penis's penises penitence penitence's penitent penitentiaries penitentiary penitentiary's penitents penknife penknife's penknives penmanship penmanship's pennant pennant's pennants penned pennies penniless penning penny penny's pens pension pension's pensioned pensioner pensioners pensioning pensions pensive pensively pentagon pentagon's pentagonal pentagonals pentagons penthouse penthouse's penthoused penthouses penthousing penultimate peon peon's peonies peons peony peony's people people's peopled peoples peopling pep pep's pepped pepper pepper's peppered peppering peppermint peppermint's peppermints pepperoni pepperonis peppers peppier peppiest pepping peppy peps per perceive perceived perceives perceiving percent percent's percentage percentage's percentages percentile percentile's percentiles percents perceptible perceptibly perception perception's perceptions perceptive perceptively perch perch's perchance perched perches perching percolate percolated percolates percolating percolation percolation's percolator percolator's percolators percussion percussion's peremptory perennial perennials perfect perfected perfecter perfectest perfecting perfection perfection's perfectionist perfectionist's perfectionists perfections perfectly perfects perforate perforated perforates perforating perforation perforations perform performance performance's performances performed performer performer's performers performing performs perfume perfume's perfumed perfumes perfuming perfunctorily perfunctory perhaps perhapses peril peril's perilled perilling perilous perilously perils perimeter perimeter's perimeters period period's periodic periodical periodical's periodically periodicals periods peripheral peripherals peripheries periphery periphery's periscope periscope's periscoped periscopes periscoping perish perishable perishables perished perishes perishing perjure perjured perjures perjuries perjuring perjury perjury's perk perked perkier perkiest perking perks perky perm perm's permanence permanence's permanent permanently permanents permeate permeated permeates permeating permed perming permissible permission permission's permissions permissive permit permits permitted permitting perms permutation permutation's permutations pernicious peroxide peroxide's peroxided peroxides peroxiding perpendicular perpendiculars perpetrate perpetrated perpetrates perpetrating perpetrator perpetrator's perpetrators perpetual perpetually perpetuals perpetuate perpetuated perpetuates perpetuating perplex perplexed perplexes perplexing perplexities perplexity perplexity's perquisite perquisite's perquisites persecute persecuted persecutes persecuting persecution persecution's persecutions persecutor persecutor's persecutors perseverance perseverance's persevere persevered perseveres persevering persist persisted persistence persistence's persistent persistently persisting persists person person's persona persona's personable personae personal personalise personalised personalises personalising personalities personality personality's personally personals personification personification's personifications personified personifies personify personifying personnel personnel's persons perspective perspective's perspectives perspiration perspiration's perspire perspired perspires perspiring persuade persuaded persuades persuading persuasion persuasion's persuasions persuasive persuasively persuasiveness persuasiveness's pert pertain pertained pertaining pertains perter pertest pertinent pertinents perts perturb perturbed perturbing perturbs perusal perusal's perusals peruse perused peruses perusing pervade pervaded pervades pervading pervasive perverse perversely perversion perversion's perversions perversity perversity's pervert perverted perverting perverts peskier peskiest pesky pessimism pessimism's pessimist pessimist's pessimistic pessimistically pessimists pest pest's pester pestered pestering pesters pesticide pesticide's pesticides pestilence pestilence's pestilences pests pet pet's petal petal's petals peter petered petering peters petite petites petition petition's petitioned petitioning petitions petrified petrifies petrify petrifying petrol petrol's petroleum petroleum's pets petted petticoat petticoat's petticoats pettier petties pettiest pettiness petting petty petulant petunia petunia's petunias pew pew's pews pewter pewter's pewters phalli phallic phallus phallus's phalluses phantom phantom's phantoms pharmaceutical pharmaceuticals pharmacies pharmacist pharmacist's pharmacists pharmacologist pharmacologist's pharmacologists pharmacology pharmacology's pharmacy pharmacy's phase phase's phased phases phasing pheasant pheasant's pheasants phenomena phenomena's phenomenal phenomenally phenomenas phenomenon phenomenon's phenomenons philanthropic philanthropies philanthropist philanthropist's philanthropists philanthropy philanthropy's philistine philistines philosopher philosopher's philosophers philosophical philosophically philosophies philosophise philosophised philosophises philosophising philosophy philosophy's phlegm phlegm's phlegmatic phobia phobia's phobias phobic phobics phoenix phoenix's phoenixes phone phone's phoned phones phonetic phonetically phonetics phonetics's phoney phonics phonics's phonied phonier phonies phoniest phoning phonograph phonograph's phonographs phony phonying phooey phooeys phosphate phosphate's phosphates phosphor phosphor's phosphorescence phosphorescence's phosphorescent phosphorus phosphorus's photo photo's photocopied photocopier photocopier's photocopiers photocopies photocopy photocopy's photocopying photoed photogenic photograph photograph's photographed photographer photographer's photographers photographic photographing photographs photography photography's photoing photon photons photos photosynthesis photosynthesis's photosynthesise photosynthesised photosynthesises photosynthesising phototypesetter phrase phrase's phrased phraseology phraseology's phrases phrasing phrasing's phrasings physic physical physically physicals physician physician's physicians physicist physicist's physicists physics physiological physiology physiology's physiotherapy physiotherapy's physique physique's physiques pi pianist pianist's pianists piano piano's pianos piccolo piccolo's piccolos pick pickax pickax's pickaxe pickaxed pickaxes pickaxing picked picker picker's pickers picket picket's picketed picketing pickets pickier pickiest picking pickle pickle's pickled pickles pickling pickpocket pickpocket's pickpockets picks pickup pickups picky picnic picnic's picnicked picnicking picnics pictorial pictorials picture picture's pictured pictures picturesque picturing piddle piddled piddles piddling pidgin pidgin's pidgins pie pie's piece piece's pieced piecemeal pieces piecework piecework's piecing pier pier's pierce pierced pierces piercing piercings piers pies piety piety's pig pig's pigeon pigeon's pigeoned pigeonhole pigeonhole's pigeonholed pigeonholes pigeonholing pigeoning pigeons pigged piggier piggies piggiest pigging piggish piggy piggy's piggyback piggyback's piggybacked piggybacking piggybacks pigheaded piglet piglet's piglets pigment pigment's pigmentation pigmentation's pigments pigpen pigpen's pigpens pigs pigsties pigsty pigsty's pigtail pigtail's pigtails pike pike's piked pikes piking pile pile's piled piles pileup pileup's pileups pilfer pilfered pilfering pilfers pilgrim pilgrim's pilgrimage pilgrimage's pilgrimages pilgrims piling piling's pilings pill pill's pillage pillaged pillages pillaging pillar pillar's pillars pillow pillow's pillowcase pillowcase's pillowcases pillowed pillowing pillows pills pilot pilot's piloted piloting pilots pimp pimp's pimped pimping pimple pimple's pimples pimplier pimpliest pimply pimply's pimps pin pin's pincer pincers pinch pinched pinches pinching pincushion pincushion's pincushions pine pine's pineapple pineapple's pineapples pined pines ping ping's pinged pinging pings pining pinion pinion's pinioned pinioning pinions pink pink's pinked pinker pinkest pinkie pinkie's pinkies pinking pinks pinky pinnacle pinnacle's pinnacles pinned pinning pinpoint pinpointed pinpointing pinpoints pinprick pinprick's pinpricked pinpricking pinpricks pins pinstripe pinstripe's pinstripes pint pint's pints pinup pinup's pinups pioneer pioneer's pioneered pioneering pioneers pious piously pipe pipe's piped pipeline pipeline's pipelines pipes piping piping's pipsqueak pipsqueak's pipsqueaks piquancy piquancy's piquant pique pique's piqued piques piquing piracy piracy's piranha piranha's piranhas pirate pirate's pirated pirates pirating pirouette pirouette's pirouetted pirouettes pirouetting pis piss pissed pisses pissing pistachio pistachio's pistachios pistol pistol's pistols piston piston's pistons pit pit's pitch pitched pitcher pitcher's pitchers pitches pitchfork pitchfork's pitchforked pitchforking pitchforks pitching piteous piteously pitfall pitfall's pitfalls pithier pithiest pithy pitied pities pitiful pitifuller pitifullest pitifully pitiless pits pittance pittance's pittances pitted pitting pity pity's pitying pivot pivot's pivotal pivoted pivoting pivots pixel pixel's pixels pixie pixie's pixies pixy pizza pizza's pizzas pizzazz pj's placard placard's placarded placarding placards placate placated placates placating place place's placebo placebo's placeboes placebos placed placement placement's placenta placenta's placentae placentas places placid placidly placing plagiarise plagiarised plagiarises plagiarising plagiarism plagiarism's plagiarisms plagiarist plagiarist's plagiarists plague plague's plagued plagues plaguing plaice plaice's plaid plaid's plaided plaiding plaids plain plainclothes plainer plainest plainly plains plaintiff plaintiff's plaintiffs plaintive plan plan's planar plane plane's planed planes planet planet's planetaria planetarium planetarium's planetariums planetary planets planing plank plank's planked planking planks plankton plankton's planned planner planners planning plannings plans plant plant's plantain plantain's plantains plantation plantation's plantations planted planter planter's planters planting plantings plants plaque plaque's plaques plasma plasma's plaster plaster's plastered plastering plasters plastic plastic's plastics plate plate's plateau plateau's plateaued plateauing plateaus plateaux plated plateful platefuls plates platform platform's platformed platforming platforms plating plating's platinum platinum's platitude platitude's platitudes platonic platoon platoon's platooned platooning platoons platter platter's platters plausibility plausible plausibly play playable playback playback's playboy playboy's playboys played player player's players playful playfully playfulness playfulness's playground playground's playgrounds playhouse playhouse's playhouses playing playmate playmate's playmates playoff playoffs playpen playpen's playpens playroom playroom's playrooms plays plaything plaything's playthings playwright playwright's playwrights plaza plaza's plazas plea plea's plead pleaded pleading pleading's pleads pleas pleasant pleasanter pleasantest pleasantly pleasantries pleasantry pleasantry's please pleased pleases pleasing pleasings pleasurable pleasure pleasure's pleasured pleasures pleasuring pleat pleat's pleated pleating pleats pled pledge pledge's pledged pledges pledging plenaries plenary plentiful plentifully plenty plenty's plethora plethora's pliable pliant plied pliers plies plight plight's plighted plighting plights plod plodded plodding ploddings plods plop plop's plopped plopping plops plot plot's plots plotted plotter plotter's plotters plotting plough plough's ploughed ploughing ploughs ploy ploy's ploys pluck plucked pluckier pluckiest plucking plucks plucky plug plug's plugged plugging plugs plum plum's plumage plumage's plumb plumbed plumber plumber's plumbers plumbing plumbing's plumbs plume plume's plumed plumes pluming plummet plummeted plummeting plummets plump plumped plumper plumpest plumping plumps plums plunder plundered plundering plunders plunge plunged plunger plunger's plungers plunges plunging plunk plunked plunking plunks plural pluralities plurality plurality's plurals plus pluses plush plush's plusher plushest plussed plusses plussing plutocracies plutocracy plutocracy's plutonium plutonium's ply plying plywood plywood's pneumatic pneumonia pneumonia's poach poached poacher poacher's poachers poaches poaching pocket pocket's pocketbook pocketbook's pocketbooks pocketed pocketful pocketful's pocketfuls pocketing pocketknife pocketknife's pocketknives pockets pockmark pockmark's pockmarked pockmarking pockmarks pod pod's podded podding podia podiatrist podiatrist's podiatrists podiatry podiatry's podium podium's podiums pods poem poem's poems poet poet's poetic poetical poetically poetry poetry's poets pogrom pogrom's pogromed pogroming pogroms poignancy poignancy's poignant poignantly poinsettia poinsettia's poinsettias point point's pointed pointedly pointer pointer's pointers pointier pointiest pointing pointing's pointless pointlessly pointlessness pointlessness's points pointy poise poise's poised poises poising poison poison's poisoned poisoning poisoning's poisonings poisonous poisons poke poked poker poker's pokers pokes pokey pokier pokiest poking poky polar polarisation polarisation's polarise polarised polarises polarising polarities polarity polarity's polars pole pole's poled polemic polemical polemics poles police police's policed policeman policeman's policemen polices policewoman policewoman's policewomen policies policing policy policy's poling polio polio's polios polish polished polishes polishing polite politely politeness politeness's politer politest political politically politician politician's politicians politicise politicised politicises politicising politics politics's polka polka's polkaed polkaing polkas poll poll's polled pollen pollen's pollinate pollinated pollinates pollinating pollination pollination's polling polls pollster pollster's pollsters pollutant pollutant's pollutants pollute polluted pollutes polluting pollution pollution's polo polo's polyester polyester's polyesters polygamist polygamist's polygamists polygamous polygamy polygamy's polygon polygon's polygons polygraph polygraph's polygraphed polygraphing polygraphs polymer polymer's polymers polynomial polynomials polyp polyp's polyps polytechnic polytechnic's polytechnics pomegranate pomegranate's pomegranates pomp pomp's pompom pompom's pompoms pomposity pomposity's pompous poncho poncho's ponchos pond pond's ponder pondered pondering ponderous ponders ponds ponies pontiff pontiff's pontiffs pontifical pontoon pontoon's pontooned pontooning pontoons pony pony's ponytail ponytail's ponytails pooch pooch's pooched pooches pooching poodle poodle's poodles pool pool's pooled pooling pools poop poop's pooped pooping poops poor poorer poorest poorly pop popcorn popcorn's pope pope's poplar poplar's poplars popped poppies popping poppy poppy's pops populace populace's populaces popular popularise popularised popularises popularising popularity popularity's popularly populars populate populated populates populating population population's populations populous porcelain porcelain's porch porch's porches porcupine porcupine's porcupines pore pored pores poring pork pork's porn pornographer pornographer's pornographers pornographic pornography pornography's porous porpoise porpoise's porpoised porpoises porpoising porridge porridge's port port's portability portable portables portal portal's portals ported portend portended portending portends portent portent's portents porter porter's portered portering porters portfolio portfolio's portfolios porthole porthole's portholes portico portico's porticoes porticos porting portion portion's portioned portioning portions portlier portliest portly portrait portrait's portraits portray portrayal portrayal's portrayals portrayed portraying portrays ports pose posed poses posh poshed posher poshes poshest poshing posies posing position position's positional positioned positioning positions positive positively positiver positives positivest positivism positivism's posse posse's posses possess possessed possesses possessing possession possession's possessions possessive possessives possessor possessor's possessors possibilities possibility possibility's possible possibler possibles possiblest possibly possum possum's possums post post's postage postage's postal postbox postbox's postcard postcard's postcards postcode postcode's postdate postdated postdates postdating postdoc postdocs postdoctoral posted poster poster's posterior posteriors posterity posterity's posters postgraduate postgraduate's postgraduates posthumous posthumously posting posting's postman postman's postmark postmark's postmarked postmarking postmarks postmaster postmaster's postmasters postmen postmortem postmortems postpone postponed postponement postponements postpones postponing posts postscript postscript's postscripts postulate postulated postulates postulating posture posture's postured postures posturing postwar posy posy's pot pot's potassium potassium's potato potato's potatoes potbellied potbellies potbelly potbelly's potency potency's potent potential potentially pothole pothole's potholed potholes potholing potion potion's potions potluck potluck's potlucks potpourri potpourri's potpourris pots potted potter potter's pottered potteries pottering potters pottery pottery's pottier potties pottiest potting potty pouch pouch's pouched pouches pouching poultry poultry's pounce pounced pounces pouncing pound pounded pounding pounds pour poured pouring pours pout pouted pouting pouts poverty poverty's powder powder's powdered powdering powders powdery power power's powerboat powerboat's powerboats powered powerful powerfully powerhouse powerhouse's powerhouses powering powerless powerlessness powerlessness's powers powwow powwow's powwowed powwowing powwows practicable practical practicalities practicality practicality's practically practicals practise practise's practised practises practising practitioner practitioner's practitioners pragmatic pragmatics pragmatism pragmatism's pragmatist pragmatist's pragmatists prairie prairie's prairies praise praise's praised praises praiseworthy praising pram pram's prance pranced prances prancing prank prank's pranks prankster prankster's pranksters prattle prattled prattles prattling prawn prawn's prawned prawning prawns pray prayed prayer prayer's prayers praying prays preach preached preacher preacher's preachers preaches preaching preamble preamble's preambled preambles preambling precarious precariously precaution precaution's precautionary precautions precede preceded precedence precedence's precedent precedent's precedents precedes preceding precept precept's precepts precinct precinct's precincts precious precipice precipice's precipices precipitate precipitated precipitates precipitating precipitation precipitation's precipitations precipitous precise precisely preciser precises precisest precision precision's preclude precluded precludes precluding precocious preconceive preconceived preconceives preconceiving preconception preconception's preconceptions precondition precondition's preconditioned preconditioning preconditions precursor precursor's precursors predate predated predates predating predator predator's predators predatory predecessor predecessor's predecessors predefined predestination predestination's predestine predestined predestines predestining predetermine predetermined predetermines predetermining predicament predicament's predicaments predicate predicated predicates predicating predict predictable predictably predicted predicting prediction prediction's predictions predictor predictor's predicts predilection predilection's predilections predispose predisposed predisposes predisposing predisposition predisposition's predispositions predominance predominance's predominant predominantly predominate predominated predominates predominating preeminence preeminence's preeminent preempt preempted preempting preemptive preempts preen preened preening preens preexist preexisted preexisting preexists prefab prefab's prefabbed prefabbing prefabricate prefabricated prefabricates prefabricating prefabs preface preface's prefaced prefaces prefacing prefect prefect's prefer preferable preferably preference preference's preferences preferential preferred preferring prefers prefix prefix's prefixed prefixes prefixing pregnancies pregnancy pregnancy's pregnant prehistoric prehistory prehistory's prejudge prejudged prejudges prejudging prejudice prejudice's prejudiced prejudices prejudicial prejudicing preliminaries preliminary prelude prelude's preludes premarital premature prematurely premeditate premeditated premeditates premeditating premeditation premeditation's premier premier's premiere premiere's premiered premieres premiering premiers premise premised premises premising premium premium's premiums premonition premonition's premonitions prenatal preoccupation preoccupation's preoccupations preoccupied preoccupies preoccupy preoccupying prep prep's prepaid preparation preparation's preparations preparatory prepare prepared preparedness preparedness's prepares preparing prepay prepaying prepays preponderance preponderance's preponderances preposition preposition's prepositional prepositioned prepositioning prepositions preposterous prepped preppie preppier preppies preppiest prepping preppy preps preregister preregistered preregistering preregisters preregistration preregistration's prerequisite prerequisites prerogative prerogative's prerogatives presage presage's presaged presages presaging preschool preschooler preschoolers preschools prescribe prescribed prescribes prescribing prescription prescription's prescriptions prescriptive presence presence's presences present presentable presentation presentation's presentations presented presenter presenting presently presents preservation preservation's preservative preservative's preservatives preserve preserved preserves preserving preside presided presidencies presidency presidency's president president's presidential presidents presides presiding press pressed presses pressing pressings pressure pressure's pressured pressures pressuring pressurise pressurised pressurises pressurising prestige prestige's prestigious presto presumably presume presumed presumes presuming presumption presumption's presumptions presumptuous presuppose presupposed presupposes presupposing presupposition presuppositions pretence pretence's pretences pretencion pretencion's pretencions pretend pretended pretender pretender's pretenders pretending pretends pretentious pretentiously pretentiousness pretext pretext's pretexted pretexting pretexts prettied prettier pretties prettiest prettily pretty prettying pretzel pretzel's pretzels prevail prevailed prevailing prevails prevalence prevalence's prevalent prevalents prevent preventable prevented preventing prevention prevention's preventive preventives prevents preview preview's previewed previewer previewers previewing previews previous previously prewar prey prey's preyed preyer preying preys price price's priced priceless prices pricey pricier priciest pricing prick pricked pricking prickle prickle's prickled prickles pricklier prickliest prickling prickly pricks pricy pride pride's prided prides priding pried prier pries priest priest's priestess priestess's priestesses priesthood priesthood's priesthoods priests prim primacy primacy's primal primaries primarily primary primate primate's primates prime primed primer primer's primers primes primeval priming priming's primitive primitives primly primmer primmest primordial primordials primp primped primping primps primrose primrose's primrosed primroses primrosing prince prince's princelier princeliest princely princes princess princess's princesses principal principalities principality principality's principally principals principle principle's principled principles principling print printable printed printer printer's printers printing printing's printings printout printouts prints prior priorities prioritise prioritised prioritises prioritising priority priority's priors prise prise's prised prises prising prism prism's prisms prison prison's prisoned prisoner prisoner's prisoners prisoning prisons prissier prissies prissiest prissy pristine privacy privacy's private privately privater privates privatest privation privation's privations privatisation privatisations privatise privatised privatises privatising privier privies priviest privilege privilege's privileged privileges privileging privy pro probabilistic probabilities probability probability's probable probables probably probation probation's probe probed probes probing problem problem's problematic problematics problems procedural procedure procedure's procedures proceed proceeded proceeding proceeding's proceedings proceeds process process's processed processes processing procession procession's processional processionals processioned processioning processions processor processor's processors proclaim proclaimed proclaiming proclaims proclamation proclamation's proclamations procrastinate procrastinated procrastinates procrastinating procrastination procrastination's procreate procreated procreates procreating procure procured procurement procurement's procures procuring prod prodded prodding prodigal prodigals prodigies prodigious prodigy prodigy's prods produce produced producer producer's producers produces producing product product's production production's productions productive productivity productivity's products prof prof's profane profaned profanes profaning profanities profanity profanity's profess professed professes professing profession profession's professional professionalism professionalism's professionally professionals professions professor professor's professors proffer proffered proffering proffers proficiency proficiency's proficient proficiently proficients profile profile's profiled profiles profiling profit profit's profitability profitability's profitable profitably profited profiteer profiteer's profiteered profiteering profiteers profiting profits profound profounder profoundest profoundly profs profundities profundity profundity's profuse profusely profusion profusion's profusions progeny progeny's prognoses prognosis prognosis's program program's programed programing programmable programme programme's programmed programmer programmer's programmers programmes programming programs progress progress's progressed progresses progressing progression progression's progressions progressive progressively progressives prohibit prohibited prohibiting prohibition prohibition's prohibitions prohibitive prohibitively prohibits project project's projected projectile projectile's projectiles projecting projection projection's projections projector projector's projectors projects proletarian proletarians proletariat proletariat's proliferate proliferated proliferates proliferating proliferation proliferation's prolific prologue prologue's prologues prolong prolonged prolonging prolongs prom prom's promenade promenade's promenaded promenades promenading prominence prominence's prominent prominently promiscuity promiscuity's promiscuous promise promised promises promising promo promontories promontory promontory's promos promote promoted promoter promoter's promoters promotes promoting promotion promotion's promotional promotions prompt prompted prompter promptest prompting promptings promptly promptness promptness's prompts proms promulgate promulgated promulgates promulgating prone prong prong's prongs pronoun pronoun's pronounce pronounced pronouncement pronouncement's pronouncements pronounces pronouncing pronouns pronto pronunciation pronunciation's pronunciations proof proof's proofed proofing proofread proofreading proofreads proofs prop propaganda propaganda's propagandise propagandised propagandises propagandising propagate propagated propagates propagating propagation propagation's propel propelled propeller propeller's propellers propelling propels propensities propensity propensity's proper properer properest properly properties property property's prophecies prophecy prophecy's prophesied prophesies prophesy prophesying prophet prophet's prophetic prophets propitious proponent proponent's proponents proportion proportion's proportional proportionality proportionality's proportionally proportionals proportionate proportioned proportioning proportions proposal proposal's proposals propose proposed proposes proposing proposition proposition's propositional propositioned propositioning propositions propped propping proprietaries proprietary proprietor proprietor's proprietors propriety propriety's props propulsion propulsion's pros prosaic proscribe proscribed proscribes proscribing proscription proscription's proscriptions prose prose's prosecute prosecuted prosecutes prosecuting prosecution prosecution's prosecutions prosecutor prosecutor's prosecutors proselytise proselytised proselytises proselytising proses prospect prospect's prospected prospecting prospective prospectives prospector prospector's prospectors prospects prospectus prospectus's prospectuses prosper prospered prospering prosperity prosperity's prosperous prospers prosses prostheses prosthesis prosthesis's prostitute prostitute's prostituted prostitutes prostituting prostitution prostitution's prostrate prostrated prostrates prostrating protagonist protagonist's protagonists protect protected protecting protection protection's protections protective protectives protector protector's protectors protects protein protein's proteins protest protest's protestant protested protester protester's protesters protesting protestor protestors protests protocol protocol's protocols proton proton's protons prototype prototype's prototypes protract protracted protracting protraction protraction's protractor protractor's protractors protracts protrude protruded protrudes protruding protrusion protrusion's protrusions protg protg's protgs proud prouder proudest proudly provable provably prove proved proven provenance provenance's proverb proverb's proverbial proverbs proves provide provided providence providence's provident provider provider's provides providing province province's provinces provincial provincials proving provision provision's provisional provisionally provisioned provisioning provisions proviso proviso's provisoes provisos provocation provocation's provocations provocative provoke provoked provokes provoking provost provost's provosts prow prow's prowess prowess's prowl prowled prowler prowler's prowlers prowling prowls prows proxies proximity proximity's proxy proxy's prude prude's prudence prudence's prudent prudently prudes prudish prune prune's pruned prunes pruning prurience prurience's prurient pry prying prys prcis prcis's prcised prcising psalm psalm's psalms pseudo pseudonym pseudonym's pseudonyms psych psyche psyche's psyched psychedelic psychedelics psyches psychiatric psychiatrist psychiatrist's psychiatrists psychiatry psychiatry's psychic psychics psyching psycho psycho's psychoanalyse psychoanalysed psychoanalyses psychoanalysing psychoanalysis psychoanalysis's psychoanalyst psychoanalysts psychological psychologically psychologies psychologist psychologist's psychologists psychology psychology's psychopath psychopath's psychopathic psychopathics psychopaths psychos psychoses psychosis psychosis's psychosomatic psychosomatics psychotherapies psychotherapist psychotherapist's psychotherapists psychotherapy psychotherapy's psychotic psychotics psychs pub pub's pubbed pubbing puberty puberty's pubescence pubic public publication publication's publications publicise publicised publicises publicising publicist publicist's publicists publicity publicity's publicly publish published publisher publisher's publishers publishes publishing publishing's pubs puck puck's pucked pucker puckered puckering puckers pucking pucks pudding pudding's puddings puddle puddle's puddled puddles puddling pudgier pudgiest pudgy pueblo pueblo's pueblos puerile puff puff's puffed puffer puffier puffiest puffing puffs puffy pugnacious puke puked pukes puking pull pulled pulley pulley's pulleys pulling pullout pullouts pullover pullover's pullovers pulls pulmonary pulp pulp's pulped pulping pulpit pulpit's pulpits pulps pulsate pulsated pulsates pulsating pulsation pulsation's pulsations pulse pulse's pulsed pulses pulsing pulverisation pulverisation's pulverise pulverised pulverises pulverising puma puma's pumas pumice pumice's pumices pummel pummelled pummelling pummels pump pump's pumped pumpernickel pumpernickel's pumping pumping's pumpkin pumpkin's pumpkins pumps pun pun's punch punched punches punching punchline punctual punctuality punctuality's punctuate punctuated punctuates punctuating punctuation punctuation's puncture puncture's punctured punctures puncturing pundit pundit's pundits pungent punier puniest punish punishable punished punishes punishing punishment punishment's punishments punitive punk punk's punker punkest punks punned punning puns punt punt's punted punter punter's punters punting punts puny pup pup's pupil pupil's pupils pupped puppet puppet's puppeteer puppeteer's puppeteers puppets puppied puppies pupping puppy puppy's puppying pups purchase purchased purchaser purchaser's purchasers purchases purchasing pure pured puree puree's pureed pureeing purees purely purer pures purest purgatories purgatory purgatory's purge purged purges purging purification purified purifies purify purifying puring purist purist's purists puritan puritan's puritanical puritans purity purity's purple purple's purpler purples purplest purport purported purporting purports purpose purpose's purposed purposeful purposely purposes purposing purr purred purring purrs purse purse's pursed purser purser's pursers purses pursing pursue pursued pursues pursuing pursuit pursuit's pursuits purvey purveyed purveying purveyor purveyor's purveyors purveys pus pus's push pushed pusher pusher's pushers pushes pushier pushiest pushing pushover pushover's pushovers pushy puss pusses pussier pussies pussiest pussy pussy's pussycat pussycats pussyfoot pussyfooted pussyfooting pussyfoots put putative putrid puts putt putt's putted putter putter's puttered puttering putters puttied putties putting putts putty putty's puttying puzzle puzzled puzzles puzzling pygmies pygmy pygmy's pyjamas pylon pylon's pylons pyramid pyramid's pyramided pyramides pyramiding pyramids pyre pyre's pyres python python's pythons pres q qua quack quacked quacking quacks quad quad's quadrangle quadrangle's quadrangles quadrant quadrant's quadrants quadratic quadratic's quadrilateral quadrilaterals quadruped quadruped's quadrupeds quadruple quadrupled quadruples quadruplet quadruplet's quadruplets quadrupling quads quagmire quagmire's quagmired quagmires quagmiring quail quail's quailed quailing quails quaint quainter quaintest quake quaked quakes quaking qualification qualification's qualifications qualified qualifier qualifier's qualifiers qualifies qualify qualifying qualitative qualities quality quality's qualm qualm's qualms quandaries quandary quandary's quantified quantifier quantifier's quantifiers quantifies quantify quantifying quantitative quantities quantity quantity's quantum quantum's quarantine quarantine's quarantined quarantines quarantining quark quark's quarks quarrel quarrel's quarrelled quarrelling quarrels quarrelsome quarried quarries quarry quarry's quarrying quart quart's quarter quarter's quarterback quarterback's quarterbacked quarterbacking quarterbacks quartered quarterfinal quarterfinal's quarterfinals quartering quarterlies quarterly quarters quartet quartet's quartets quarts quartz quartz's quash quashed quashes quashing quaver quavered quavering quavers quay quay's quays queasier queasiest queasiness queasiness's queasy queen queen's queened queening queenlier queenliest queenly queens queer queered queerer queerest queering queers quell quelled quelling quells quench quenched quenches quenching queried queries query query's querying quest quest's quested questing question question's questionable questioned questioning questionnaire questionnaire's questionnaires questions quests queue queue's queued queueing queues quibble quibbled quibbles quibbling quiche quiche's quiches quick quicken quickened quickening quickens quicker quickest quickie quickie's quickies quickly quicksand quicksand's quicksands quiet quieted quieter quieter's quietest quieting quietly quietness quietness's quiets quill quill's quills quilt quilt's quilted quilting quilts quinine quinine's quintessence quintessence's quintessences quintessential quintet quintet's quintets quintuplet quintuplet's quintuplets quip quip's quipped quipping quips quirk quirk's quirked quirkier quirkiest quirking quirks quirky quit quite quited quites quiting quits quitted quitter quitters quitting quiver quivered quivering quivers quixotic quiz quiz's quizes quizzed quizzes quizzical quizzing quorum quorum's quorums quota quota's quotable quotas quotation quotation's quotations quote quoted quotes quotient quotient's quotients quoting r rabbi rabbi's rabbies rabbis rabbit rabbit's rabbited rabbiting rabbits rabble rabble's rabbles rabid rabies raccoon raccoon's raccoons race race's raced racer racer's races racetrack racetrack's racetracks racial racially racier raciest racing racism racist racist's racists rack rack's racked racket racket's racketed racketeer racketeer's racketeered racketeering racketeers racketing rackets racking racks racoon racy radar radar's radars radial radials radiance radiance's radiant radiate radiated radiates radiating radiation radiation's radiations radiator radiator's radiators radical radically radicals radii radii's radio radio's radioactive radioactivity radioactivity's radioed radioing radiologist radiologist's radiologists radiology radiology's radios radiotherapy radiotherapy's radish radish's radishes radium radium's radius radius's radiuses radon radon's raffle raffle's raffled raffles raffling raft raft's rafted rafter rafter's rafters rafting rafts rag rag's ragamuffin ragamuffin's ragamuffins rage rage's raged rages ragged raggeder raggedest ragging raging rags ragtag ragtag's ragtags ragtime ragtime's raid raid's raided raider raider's raiders raiding raids rail rail's railed railing railing's railroad railroad's railroaded railroading railroads rails railway railway's railways rain rain's rainbow rainbow's rainbows raincoat raincoat's raincoats raindrop raindrop's raindrops rained rainfall rainfall's rainfalls rainforest rainforest's rainier rainiest raining rains rainstorm rainstorm's rainstorms rainwater rainwater's rainy raise raised raises raisin raisin's raising raising's raisins rake rake's raked rakes raking rallied rallies rally rallying ram ram's ramble rambled rambler rambler's ramblers rambles rambling ramblings rambunctious ramification ramification's ramifications rammed ramming ramp ramp's rampage rampaged rampages rampaging rampant ramps ramrod ramrod's ramrodded ramrodding ramrods rams ramshackle ran ranch ranch's ranched rancher rancher's ranchers ranches ranching rancid rancorous rancour random randomly randomness randomness's rang range range's ranged ranger ranger's rangers ranges ranging rank rank's ranked ranker rankest ranking rankings rankle rankled rankles rankling ranks ransack ransacked ransacking ransacks ransom ransom's ransomed ransoming ransoms rant ranted ranting rants rap rape rape's raped rapes rapid rapider rapidest rapidity rapidity's rapidly rapids raping rapist rapist's rapists rapped rapping rapport rapport's rapports rapprochement rapprochement's rapprochements raps rapt rapture rapture's raptures rapturous rare rared rarely rarer rares rarest raring rarities rarity rarity's rascal rascal's rascals rash rasher rashes rashest rashly rasp rasp's raspberries raspberry raspberry's rasped raspier raspiest rasping rasps raspy raster raster's rat rat's rate rate's rated rates rather ratification ratified ratifies ratify ratifying rating rating's ratings ratio ratio's ration ration's rational rationale rationale's rationales rationalisation rationalisation's rationalisations rationalise rationalised rationalises rationalising rationality rationality's rationally rationals rationed rationing rations ratios rats ratted ratting rattle rattled rattler rattlers rattles rattlesnake rattlesnake's rattlesnakes rattling ratty raucous raucously raunchier raunchiest raunchy ravage ravaged ravages ravaging rave raved ravel ravelled ravelling ravellings ravels raven raven's ravened ravening ravenous ravenously ravens raves ravine ravine's ravined ravines raving ravings ravining ravish ravished ravishes ravishing raw rawer rawest ray ray's rayon rayon's rays raze razed razes razing razor razor's razors razz razzed razzes razzing re re's reach reached reaches reaching react reacted reacting reaction reaction's reactionaries reactionary reactions reactive reactor reactor's reactors reacts read readability readability's readable reader reader's readers readership readership's readerships readied readier readies readiest readily readiness readiness's reading reading's readings readjust readjusted readjusting readjustment readjustment's readjustments readjusts reads ready readying real realer realest realisation realisation's realise realised realises realising realism realism's realist realist's realistic realistically realists realities reality reality's reallied reallies reallocate reallocated reallocates reallocating really reallying realm realm's realms realty realty's ream ream's reamed reaming reams reap reaped reaper reaper's reapers reaping reappear reappearance reappearance's reappearances reappeared reappearing reappears reaps rear rear's reared rearing rearrange rearranged rearrangement rearrangement's rearrangements rearranges rearranging rears reason reason's reasonable reasonableness reasonableness's reasonably reasoned reasoning reasoning's reasons reassurance reassurance's reassurances reassure reassured reassures reassuring reassuringly rebate rebate's rebated rebates rebating rebel rebelled rebelling rebellion rebellion's rebellions rebellious rebels rebind rebinding rebinds rebirth rebirth's rebirths reborn rebound rebounded rebounding rebounds rebuff rebuffed rebuffing rebuffs rebuild rebuilding rebuilds rebuilt rebuke rebuked rebukes rebuking rebut rebuts rebuttal rebuttal's rebuttals rebutted rebutting recalcitrance recalcitrance's recalcitrant recall recalled recalling recalls recant recanted recanting recants recap recapped recapping recaps recapture recaptured recaptures recapturing recede receded recedes receding receipt receipt's receipted receipting receipts receive received receiver receiver's receivers receivership receivership's receives receiving recent recenter recentest recently receptacle receptacle's receptacles reception reception's receptionist receptionist's receptionists receptions receptive recess recess's recessed recesses recessing recession recession's recessions recharge rechargeable recharged recharges recharging recipe recipe's recipes recipient recipient's recipients reciprocal reciprocals reciprocate reciprocated reciprocates reciprocating recital recital's recitals recitation recitation's recitations recite recited recites reciting reckless recklessly recklessness reckon reckoned reckoning reckoning's reckonings reckons reclaim reclaimed reclaiming reclaims reclamation reclamation's recline reclined reclines reclining recluse recluse's recluses recognisable recognisably recognise recognised recognises recognising recognition recognition's recoil recoiled recoiling recoils recollect recollected recollecting recollection recollection's recollections recollects recommend recommendation recommendation's recommendations recommended recommending recommends recompense recompensed recompenses recompensing recompile recompiled recompiling reconcile reconciled reconciles reconciliation reconciliations reconciling recondition reconditioned reconditioning reconditions reconfigure reconfigured reconnaissance reconnaissance's reconnaissances reconnect reconnected reconnecting reconnects reconsider reconsidered reconsidering reconsiders reconstitute reconstituted reconstitutes reconstituting reconstruct reconstructed reconstructing reconstruction reconstruction's reconstructions reconstructs record record's recorded recorder recorder's recorders recording recording's recordings records recount recounted recounting recounts recoup recouped recouping recoups recourse recourse's recover recoverable recovered recoveries recovering recovers recovery recovery's recreate recreated recreates recreating recreation recreation's recreational recreations recruit recruited recruiter recruiter's recruiters recruiting recruitment recruitment's recruits recta rectal rectangle rectangle's rectangles rectangular rectified rectifies rectify rectifying rector rector's rectors rectum rectum's rectums recuperate recuperated recuperates recuperating recuperation recuperation's recur recurred recurrence recurrence's recurrences recurrent recurring recurs recursion recursion's recursive recursively recyclable recyclables recycle recycled recycles recycling red red's redden reddened reddening reddens redder reddest reddish redeem redeemable redeemed redeeming redeems redefine redefined redefines redefining redefinition redefinition's redemption redemption's redesign redesigned redesigning redesigns redevelop redeveloped redeveloping redevelopment redevelopment's redevelopments redevelops redhead redhead's redheads redid redirect redirected redirecting redirection redirects rediscover rediscovered rediscovering rediscovers redistribute redistributed redistributes redistributing redistribution redistribution's redneck redneck's rednecks redness redness's redo redoes redoing redone redouble redoubled redoubles redoubling redraft redraft's redraw redress redressed redresses redressing reds redskin redskin's redskins reduce reduced reduces reducing reduction reduction's reductions redundancies redundancy redundancy's redundant redwood redwood's redwoods reed reed's reeds reeducate reeducated reeducates reeducating reeducation reeducation's reef reef's reefed reefing reefs reek reeked reeking reeks reel reel's reelect reelected reelecting reelection reelection's reelections reelects reeled reeling reels reenact reenacted reenacting reenactment reenactment's reenactments reenacts reentries reentry reentry's ref ref's refed refer referee referee's refereed refereeing referees reference reference's referenced references referencing referenda referendum referendum's referendums referred referring refers reffed reffing refill refilled refilling refills refinance refinanced refinances refinancing refine refined refinement refinement's refinements refineries refinery refinery's refines refining refinish refinished refinishes refinishing reflect reflected reflecting reflection reflection's reflections reflective reflector reflector's reflectors reflects reflex reflex's reflexes reflexive reflexives reform reformat reformation reformation's reformations reformatted reformatting reformed reformer reformer's reformers reforming reforms refraction refraction's refrain refrained refraining refrains refresh refreshed refreshes refreshing refreshingly refreshment refreshment's refreshments refrigerate refrigerated refrigerates refrigerating refrigeration refrigeration's refrigerator refrigerator's refrigerators refs refuel refuelled refuelling refuels refuge refuge's refugee refugee's refugees refuges refund refundable refunded refunding refunds refurbish refurbished refurbishes refurbishing refurbishment refurbishments refusal refusal's refusals refuse refuse's refused refuses refusing refutation refutation's refute refuted refutes refuting regain regained regaining regains regal regale regaled regales regalia regalia's regaling regals regard regarded regarding regardless regards regatta regatta's regattas regenerate regenerated regenerates regenerating regeneration regeneration's regent regent's regents reggae reggae's regime regime's regimen regimen's regimens regiment regiment's regimental regimentals regimented regimenting regiments regimes region region's regional regionally regions register register's registered registering registers registrar registrar's registrars registration registration's registrations registries registry registry's regress regressed regresses regressing regression regression's regressions regret regretful regretfully regrets regrettable regrettably regretted regretting regroup regrouped regrouping regroups regular regularity regularity's regularly regulars regulate regulated regulates regulating regulation regulation's regulations regurgitate regurgitated regurgitates regurgitating regurgitation regurgitation's rehab rehabbed rehabbing rehabilitate rehabilitated rehabilitates rehabilitating rehabilitation rehabilitation's rehabs rehash rehashed rehashes rehashing rehearsal rehearsal's rehearsals rehearse rehearsed rehearses rehearsing reign reign's reigned reigning reigns reimburse reimbursed reimbursement reimbursements reimburses reimbursing rein rein's reincarnate reincarnated reincarnates reincarnating reincarnation reincarnation's reincarnations reindeer reindeer's reindeers reined reinforce reinforced reinforcement reinforcement's reinforcements reinforces reinforcing reining reins reinstate reinstated reinstatement reinstatement's reinstates reinstating reinvent reinvented reinventing reinvents reissue reissued reissues reissuing reiterate reiterated reiterates reiterating reiteration reiterations reject rejected rejecting rejection rejection's rejections rejects rejoice rejoiced rejoices rejoicing rejoicings rejoin rejoinder rejoinder's rejoinders rejoined rejoining rejoins rejuvenate rejuvenated rejuvenates rejuvenating rejuvenation rekindle rekindled rekindles rekindling relaid relapse relapsed relapses relapsing relate related relates relating relation relation's relational relations relationship relationship's relationships relative relatively relatives relativistic relativity relativity's relax relaxation relaxation's relaxations relaxed relaxes relaxing relay relay's relayed relaying relays releasable release released releases releasing relegate relegated relegates relegating relent relented relenting relentless relentlessly relents relevance relevance's relevant reliability reliability's reliable reliables reliably reliance reliance's reliant relic relic's relics relied relief relief's reliefs relies relieve relieved relieves relieving religion religion's religions religious religiously relinquish relinquished relinquishes relinquishing relish relished relishes relishing relive relived relives reliving reload reload's reloaded reloading reloads relocatable relocate relocated relocates relocating relocation relocation's reluctance reluctance's reluctant reluctantly rely relying remade remain remainder remainder's remainders remained remaining remains remake remake's remakes remaking remark remarkable remarkably remarked remarking remarks remarriage remarriage's remarriages remarried remarries remarry remarrying remedial remedied remedies remedy remedy's remedying remember remembered remembering remembers remembrance remembrance's remembrances remind reminded reminder reminders reminding reminds reminisce reminisced reminiscence reminiscence's reminiscences reminiscent reminisces reminiscing remiss remission remission's remissions remit remits remittance remittance's remittances remitted remitting remnant remnant's remnants remodel remodelled remodelling remodels remorse remorse's remorseful remorseless remote remotely remoteness remoteness's remoter remotes remotest removable removables removal removal's removals remove removed remover remover's removers removes removing remunerate remunerated remunerates remunerating remuneration remuneration's remunerations renaissance rename renamed renames renaming rend render rendered rendering rendering's renderings renders rendezvous rendezvous's rendezvoused rendezvouses rendezvousing rending rendition rendition's renditioned renditioning renditions rends renegade renegade's renegaded renegades renegading renege reneged reneges reneging renew renewable renewal renewal's renewals renewed renewing renews renounce renounced renounces renouncing renovate renovated renovates renovating renovation renovation's renovations renown renown's renowned renowning renowns rent rent's rental rental's rentals rented renter renter's renters renting rents renunciation renunciation's renunciations reopen reopened reopening reopens reorganisation reorganisation's reorganisations reorganise reorganised reorganises reorganising rep rep's repaid repair repaired repairing repairs reparation reparation's repatriate repatriated repatriates repatriating repatriation repay repaying repayment repayment's repayments repays repeal repealed repealing repeals repeat repeatable repeated repeatedly repeating repeats repel repelled repellent repellents repelling repels repent repentance repentance's repentant repentants repented repenting repents repercussion repercussion's repercussions repertoire repertoire's repertoires repetition repetition's repetitions repetitious repetitive rephrase rephrased rephrases rephrasing replace replaceable replaced replacement replacement's replacements replaces replacing replay replay's replayed replaying replays replenish replenished replenishes replenishing replenishment replete repleted repletes repleting replica replica's replicas replicate replicated replicates replicating replication replication's replications replied replies reply replying report report's reported reportedly reporter reporter's reporters reporting reports repose repose's reposed reposes reposing repositories repository repository's repossess repossessed repossesses repossessing reprehensible represent representation representation's representations representative representative's representatives represented representing represents repress repressed represses repressing repression repression's repressions repressive reprieve reprieved reprieves reprieving reprimand reprimand's reprimanded reprimanding reprimands reprint reprint's reprinted reprinting reprints reprisal reprisal's reprisals reprise reprise's reprised reprises reprising reproach reproached reproaches reproaching reproduce reproduced reproduces reproducing reproduction reproduction's reproductions reproductive reprogramed reprograming reprogramme reprogrammed reprogrammes reprogramming reprove reproved reproves reproving reps reptile reptile's reptiles reptilian reptilians republic republic's republican republicans republics repudiate repudiated repudiates repudiating repudiation repudiation's repudiations repugnance repugnance's repugnant repulse repulsed repulses repulsing repulsion repulsion's repulsive reputable reputation reputation's reputations repute reputed reputedly reputes reputing request requested requesting requests requiem requiems require required requirement requirement's requirements requires requiring requisite requisites requisition requisition's requisitioned requisitioning requisitions reran reread rereading rereads reroute rerouted reroutes rerouting rerun rerunning reruns resale resale's resales reschedule rescheduled reschedules rescheduling rescind rescinded rescinding rescinds rescue rescued rescuer rescuers rescues rescuing research research's researched researcher researchers researches researching resemblance resemblance's resemblances resemble resembled resembles resembling resent resented resentful resenting resentment resentment's resentments resents reservation reservation's reservations reserve reserved reserves reserving reservoir reservoir's reservoirs reset resets resetting reshuffle reshuffle's reshuffled reshuffles reshuffling reside resided residence residence's residences residencies residency residency's resident resident's residential residents resides residing residual residuals residue residue's residues resign resignation resignation's resignations resigned resigning resigns resilience resilience's resilient resin resin's resins resist resistance resistance's resistances resistant resisted resisting resistor resistors resists resolute resolutely resoluter resolutes resolutest resolution resolution's resolutions resolve resolved resolver resolver's resolves resolving resonance resonance's resonances resonant resonate resonated resonates resonating resort resorted resorting resorts resound resounded resounding resoundingly resounds resource resource's resourced resourceful resourcefulness resourcefulness's resources resourcing respect respect's respectability respectability's respectable respectables respectably respected respectful respectfully respecting respective respectively respects respiration respiration's respirator respirator's respirators respiratory respiratory's respite respite's respites resplendent respond responded responding responds response response's responses responsibilities responsibility responsibility's responsible responsibly responsive responsiveness responsiveness's rest rest's restart restarted restarting restarts restate restated restatement restatement's restatements restates restating restaurant restaurant's restaurants rested restful restfuller restfullest resting restitution restitution's restive restless restlessly restlessness restlessness's restoration restoration's restorations restore restored restores restoring restrain restrained restraining restrains restraint restraint's restraints restrict restricted restricting restriction restriction's restrictions restrictive restrictives restricts restructure restructured restructures restructuring restructurings rests resubmit resubmits resubmitted resubmitting result result's resultant resultants resulted resulting results resume resumed resumes resuming resumption resumption's resumptions resurface resurfaced resurfaces resurfacing resurgence resurgence's resurgences resurgent resurrect resurrected resurrecting resurrection resurrection's resurrections resurrects resuscitate resuscitated resuscitates resuscitating resuscitation resuscitation's retail retail's retailed retailer retailer's retailers retailing retails retain retained retainer retainer's retainers retaining retains retake retaken retakes retaking retaliate retaliated retaliates retaliating retaliation retaliation's retaliations retard retardation retardation's retarded retarding retards retch retched retches retching retention retention's rethink rethinking rethinks rethought reticence reticent retina retina's retinae retinas retinue retinue's retinues retire retired retiree retiree's retirees retirement retirement's retirements retires retiring retook retort retorted retorting retorts retrace retraced retraces retracing retract retractable retracted retracting retraction retraction's retractions retracts retread retreaded retreading retreads retreat retreated retreating retreats retrial retrial's retrials retribution retribution's retributions retries retrieval retrieval's retrievals retrieve retrieved retriever retriever's retrievers retrieves retrieving retroactive retroactively retrod retrodden retrograde retrospect retrospect's retrospected retrospecting retrospective retrospectively retrospectives retrospects retry return returnable returnables returned returning returns retype reunion reunion's reunions reunite reunited reunites reuniting reuse reused reuses reusing rev rev's revaluation revaluation's revaluations revalue revalued revalues revaluing revamp revamped revamping revamps reveal revealed revealing revealings reveals revel revelation revelation's revelations revelled reveller revellers revelling revellings revelries revelry revelry's revels revenge revenge's revenged revengeful revenges revenging revenue revenue's revenues reverberate reverberated reverberates reverberating reverberation reverberation's reverberations revere revered reverence reverence's reverenced reverences reverencing reverent reverently reveres reverie reverie's reveries revering reversal reversal's reversals reverse reversed reverses reversible reversing reversion reversion's revert reverted reverting reverts revery review reviewed reviewer reviewers reviewing reviews revile reviled reviles reviling revise revised revises revising revision revision's revisions revisit revisited revisiting revisits revitalisation revitalisation's revitalise revitalised revitalises revitalising revival revival's revivals revive revived revives reviving revoke revoked revokes revoking revolt revolt's revolted revolting revolts revolution revolution's revolutionaries revolutionary revolutionary's revolutionise revolutionised revolutionises revolutionising revolutions revolve revolved revolver revolver's revolvers revolves revolving revs revue revue's revues revulsion revulsion's revved revving reward reward's rewarded rewarding rewards rewind rewinding rewinds rework reworked reworking reworks rewound rewrite rewrites rewriting rewritten rewrote rhapsodies rhapsody rhapsody's rhetoric rhetoric's rhetorical rhetorically rheumatism rheumatism's rhinestone rhinestone's rhinestones rhino rhino's rhinoceri rhinoceros rhinoceros's rhinoceroses rhinos rhododendron rhododendron's rhododendrons rhubarb rhubarb's rhubarbs rhyme rhyme's rhymed rhymes rhyming rhythm rhythm's rhythmic rhythmically rhythms rib rib's ribald ribbed ribbing ribbon ribbon's ribbons ribs rice rice's riced rices rich richer riches richest richly richness richness's ricing ricketier ricketiest rickety rickshaw rickshaw's rickshaws ricochet ricocheted ricocheting ricochets ricochetted ricochetting rid riddance riddance's ridded ridden ridding riddle riddle's riddled riddles riddling ride rider rider's riders rides ridge ridge's ridged ridges ridging ridicule ridicule's ridiculed ridicules ridiculing ridiculous ridiculously riding riding's rids rife rifer rifest rifle rifle's rifled rifles rifling rift rift's rifted rifting rifts rig rigged rigging rigging's right righted righteous righteously righteousness righteousness's righter rightest rightful rightfully righting rightly rightmost rightness rightness's rights rights's rigid rigidity rigidly rigmarole rigmarole's rigmaroles rigorous rigorously rigour rigour's rigours rigs rile riled riles riling rim rim's rimmed rimming rims rind rind's rinded rinding rinds ring ring's ringed ringing ringleader ringleader's ringleaders ringlet ringlet's ringlets rings ringside ringside's ringworm ringworm's rink rink's rinked rinking rinks rinse rinsed rinses rinsing riot riot's rioted rioter rioter's rioters rioting riotous riots rip ripe riped ripen ripened ripeness ripeness's ripening ripens riper ripes ripest riping riposte riposte's ripped ripper ripping ripple ripple's rippled ripples rippling rips rise risen riser riser's risers rises rising rising's risk risk's risked riskier riskiest risking risks risky risqu rite rite's rites ritual ritual's ritually rituals ritzier ritziest ritzy rival rival's rivalled rivalling rivalries rivalry rivalry's rivals rive river river's riverbed riverbeds riverfront riverfronts rivers riverside riversides rives rivet rivet's riveted riveting rivets rivetted rivetting roach roach's roaches road road's roadblock roadblock's roadblocked roadblocking roadblocks roadhouse roadhouse's roadhouses roadkill roadrunner roadrunner's roadrunners roads roadside roadsides roadway roadway's roadways roadworthy roam roamed roaming roams roar roared roaring roars roast roasted roasting roasts rob robbed robber robber's robberies robbers robbery robbery's robbing robe robe's robed robes robin robin's robing robins robot robot's robotics robots robs robust robuster robustest robustness robustness's rock rock's rocked rocker rocker's rockers rocket rocket's rocketed rocketing rockets rockier rockiest rocking rocks rocky rod rod's rode roded rodent rodent's rodents rodeo rodeo's rodeos rodes roding rods roe roe's roes rogue rogue's rogues roguish role role's roles roll rolled roller roller's rollers rollerskating rollick rollicked rollicking rollicks rolling rolls roman romance romance's romanced romances romancing romantic romantically romanticise romanticised romanticises romanticising romantics romp romped romping romps roof roof's roofed roofing roofing's roofs rooftop rooftops rook rook's rooked rookie rookie's rookier rookies rookiest rooking rooks room room's roomed roomful roomful's roomfuls roomier roomiest rooming roommate roommate's roommates rooms roomy roost roost's roosted rooster rooster's roosters roosting roosts root root's rooted rooter rooting rootless roots rope rope's roped ropes roping rosaries rosary rosary's rose rose's rosemary rosemary's roses rosier rosiest roster roster's rostered rostering rosters rostra rostrum rostrum's rostrums rosy rot rotaries rotary rotate rotated rotates rotating rotation rotation's rotations rote rote's roted rotes roting rotisserie rotisserie's rotisseries rotor rotor's rotors rots rotted rotten rottener rottenest rottens rotting rotund rotunda rotunda's rotundas rotunded rotunding rotunds rouge rouge's rouged rouges rough roughage roughage's roughed roughen roughened roughening roughens rougher roughest roughhouse roughhouse's roughhoused roughhouses roughhousing roughing roughly roughness roughness's roughs roughshod rouging roulette roulette's round roundabout roundabout's roundabouts rounded rounder roundest rounding roundness roundness's rounds roundup roundup's roundups rouse roused rouses rousing rout rout's route route's routed router router's routes routine routine's routinely routines routing routing's routs rove roved roves roving roving's row row's rowboat rowboat's rowboats rowdier rowdies rowdiest rowdiness rowdiness's rowdy rowed rowing rows royal royally royals royalties royalty royalty's rs rub rubbed rubber rubber's rubberier rubberiest rubberneck rubberneck's rubbernecked rubbernecking rubbernecks rubbers rubbery rubbing rubbing's rubbish rubbish's rubbished rubbishes rubbishing rubble rubble's rubbled rubbles rubbling rubdown rubdown's rubdowns rubella rubella's rubied rubier rubies rubiest rubric rubric's rubs ruby ruby's rubying rucksack rucksack's ruckus ruckus's ruckuses rudder rudder's rudders ruddied ruddier ruddies ruddiest ruddy ruddying rude rudely rudeness rudeness's ruder rudest rudiment rudimentary rudiments rue rued rueful rues ruff ruff's ruffed ruffian ruffian's ruffianed ruffianing ruffians ruffing ruffle ruffled ruffles ruffling ruffs rug rug's rugby rugby's rugged ruggeder ruggedest rugging rugs ruin ruin's ruined ruing ruining ruinous ruins rule rule's ruled ruler ruler's rulered rulering rulers rules ruling ruling's rulings rum rum's rumble rumbled rumbles rumbling ruminate ruminated ruminates ruminating rummage rummaged rummages rummaging rummer rummest rummy rummy's rumour rumour's rumoured rumouring rumours rump rump's rumped rumping rumple rumpled rumples rumpling rumps rums run runaround runarounds runaway runaways rundown rundown's rundowns rune runes rung rung's rungs runner runner's runners runnier runniest running runny runs runt runt's runts runway runway's runways rupture rupture's ruptured ruptures rupturing rural ruse ruse's ruses rush rushed rushes rushing rushing's rust rust's rusted rustic rustics rustier rustiest rusting rustle rustled rustler rustler's rustlers rustles rustling rustproof rustproofed rustproofing rustproofs rusts rusty rut rut's ruthless ruthlessly ruthlessness ruthlessness's ruts rutted rutting rye rye's s sabbatical sabbaticals sabotage sabotage's sabotaged sabotages sabotaging saboteur saboteur's saboteurs sabre sabre's sabres sac sac's saccharin saccharin's sack sack's sacked sacking sacks sacrament sacrament's sacramented sacramenting sacraments sacred sacrifice sacrifice's sacrificed sacrifices sacrificial sacrificing sacrilege sacrilege's sacrileges sacrilegious sacrosanct sacs sad sadden saddened saddening saddens sadder saddest saddle saddle's saddled saddles saddling sades sadism sadism's sadist sadist's sadistic sadistically sadists sadly sadness sadness's safari safari's safaried safariing safaris safe safeguard safeguard's safeguarded safeguarding safeguards safekeeping safekeeping's safekeepings safely safer safes safest safetied safeties safety safety's safetying saffron saffron's saffrons sag saga saga's sagas sage sage's sagebrush sagebrush's sager sages sagest sagged sagger sagging sags said sail sail's sailboard sailboarded sailboarding sailboards sailboat sailboat's sailboats sailed sailing sailing's sailor sailor's sailors sails saint saint's saintlier saintliest saintly saints sake sake's salad salad's salads salami salami's salamis salaried salaries salary salary's salarying sale sale's saleable sales salesclerk salesclerk's salesclerks salesman salesman's salesmen salespeople salesperson salesperson's saleswoman saleswomen salient salients saliva saliva's salivate salivated salivates salivating sallow sallower sallowest sally sally's salmon salmon's salmonella salmonella's salmonellae salmonellas salmons salon salon's salons saloon saloon's saloons salsa salsas salt salt's salted salter saltest saltier salties saltiest salting salts saltwater salty salutation salutation's salutations salute saluted salutes saluting salvage salvage's salvaged salvages salvaging salvation salvation's salve salve's salved salves salving same sameness sameness's sames sample sample's sampled sampler sampler's samples sampling sampling's sanatoria sanatorium sanatorium's sanatoriums sanctified sanctifies sanctify sanctifying sanctimonious sanction sanction's sanctioned sanctioning sanctions sanctity sanctity's sanctuaries sanctuary sanctuary's sand sand's sandal sandal's sandals sandbag sandbag's sandbagged sandbagging sandbags sandblast sandblast's sandblasted sandblasting sandblasts sandcastle sandcastles sanded sandier sandiest sanding sandman sandman's sandmen sandpaper sandpaper's sandpapered sandpapering sandpapers sands sandstone sandstone's sandstorm sandstorm's sandstorms sandwich sandwich's sandwiched sandwiches sandwiching sandy sane saned saner sanes sanest sang sangs saning sanitaria sanitaries sanitarium sanitarium's sanitariums sanitary sanitation sanitation's sanitise sanitised sanitises sanitising sanity sanity's sank sanserif sap sap's sapling sapling's sapped sapphire sapphire's sapphires sapping saps sarcasm sarcasm's sarcasms sarcastic sarcastically sardine sardine's sardined sardines sardining sardonic sari sari's saris sash sash's sashes sass sass's sassed sasses sassier sassiest sassing sassy sat satanic satanism satchel satchel's satchels satellite satellite's satellited satellites satelliting satin satin's satined satining satins satiny satire satire's satires satirical satirically satirise satirised satirises satirising satirist satirist's satirists satisfaction satisfaction's satisfactions satisfactorily satisfactory satisfied satisfies satisfy satisfying saturate saturated saturates saturating saturation saturation's sauce sauce's sauced saucepan saucepan's saucepans saucer saucer's saucers sauces saucier sauciest saucing saucy sauerkraut sauerkraut's sauna sauna's saunaed saunaing saunas saunter sauntered sauntering saunters sausage sausage's sausages sauted saut sauted sauting sauts savage savaged savagely savager savageries savagery savagery's savages savagest savaging save saved saver saver's savers saves saving savings saviour saviour's saviours savour savour's savoured savourier savouries savouriest savouring savours savoury savoury's savvied savvier savvies savviest savvy savvying saw saw's sawdust sawdust's sawdusted sawdusting sawdusts sawed sawing sawn saws sax sax's saxes saxophone saxophone's saxophones say saying saying's sayings says says's scab scab's scabbed scabbing scabs scad scads scaffold scaffold's scaffolding scaffolding's scaffolds scalar scalar's scalars scald scalded scalding scaldings scalds scale scale's scaled scales scalier scaliest scaling scallop scallop's scalloped scalloping scallops scalp scalp's scalped scalpel scalpel's scalpels scalper scalper's scalpers scalping scalps scaly scam scammed scamming scamper scampered scampering scampers scams scan scandal scandal's scandalise scandalised scandalises scandalising scandalous scandals scanned scanner scanner's scanners scanning scans scant scanted scanter scantest scantier scanties scantiest scanting scants scanty scapegoat scapegoat's scapegoated scapegoating scapegoats scar scar's scarce scarcely scarcer scarcest scarcity scarcity's scare scarecrow scarecrow's scarecrows scared scares scarf scarf's scarfed scarfing scarfs scarier scariest scaring scarlet scarlet's scarleted scarleting scarlets scarred scarring scars scarves scarves's scary scathing scatter scatterbrain scatterbrain's scatterbrained scatterbrains scattered scattering scattering's scatters scavenge scavenged scavenger scavenger's scavengers scavenges scavenging scenario scenario's scenarios scene scene's scened scenery scenery's scenes scenic scening scent scent's scented scenting scents sceptic sceptic's sceptical scepticism scepticism's sceptics sceptre sceptres schedule schedule's scheduled scheduler schedules scheduling scheme scheme's schemed schemer schemer's schemers schemes scheming schism schism's schisms schizophrenia schizophrenia's schizophrenic schizophrenics schlep schlepp schlepped schlepping schlepps schleps schlock schlock's schlockier schlockiest schlocky schmaltz schmaltz's schmaltzier schmaltziest schmaltzy schmooze schmoozed schmoozes schmoozing schmuck schmuck's schmucks scholar scholar's scholarly scholars scholarship scholarship's scholarships scholastic school school's schoolboy schoolboy's schoolboys schoolchild schoolchild's schoolchildren schooled schoolgirl schoolgirl's schoolgirls schooling schooling's schools schoolteacher schoolteacher's schoolteachers schooner schooner's schooners science science's sciences scientific scientifically scientist scientist's scientists scintillate scintillated scintillates scintillating scissor scissors scoff scoffed scoffing scoffs scold scolded scolding scoldings scolds scoop scoop's scooped scooping scoops scoot scooted scooter scooter's scooters scooting scoots scope scope's scoped scopes scoping scorch scorched scorches scorching score score's scoreboard scoreboard's scoreboards scorecard scorecard's scorecards scored scored's scorer scores scoring scorn scorn's scorned scornful scornfully scorning scorns scorpion scorpion's scorpions scotch scotch's scotched scotches scotching scotchs scoundrel scoundrel's scoundrels scour scoured scourge scourge's scourged scourges scourging scouring scours scout scout's scouted scouting scouts scowl scowled scowling scowls scrabble scrabbled scrabbles scrabbling scragglier scraggliest scraggly scram scramble scrambled scrambles scrambling scrammed scramming scrams scrap scrap's scrapbook scrapbook's scrapbooks scrape scraped scrapes scraping scrapped scrappier scrappiest scrapping scrappy scraps scratch scratched scratches scratches's scratchier scratchiest scratching scratchy scrawl scrawled scrawling scrawls scrawnier scrawniest scrawny scream screamed screaming screams screech screech's screeched screeches screeching screen screen's screened screening screening's screenplay screenplay's screenplays screens screw screw's screwball screwball's screwballs screwdriver screwdriver's screwdrivers screwed screwier screwiest screwing screws screwy scribble scribbled scribbles scribbling scribe scribe's scribes scrimp scrimped scrimping scrimps script script's scripted scripting scripts scripture scripture's scriptures scriptwriter scriptwriters scroll scroll's scrolled scrolling scrolls scrooge scrooges scrounge scrounged scrounges scrounging scrub scrubbed scrubbing scrubs scruff scruff's scruffier scruffiest scruffs scruffy scruple scruple's scrupled scruples scrupling scrupulous scrupulously scrutinise scrutinised scrutinises scrutinising scrutiny scrutiny's scuff scuffed scuffing scuffle scuffled scuffles scuffling scuffs sculptor sculptor's sculptors sculpture sculpture's sculptured sculptures sculpturing scum scum's scummed scumming scums scurried scurries scurrilous scurry scurrying scuttle scuttle's scuttled scuttles scuttling scythe scythe's scythed scythes scything sea sea's seafaring seafood seafood's seal seal's sealed sealing seals seam seam's seaman seaman's seamed seamen seaming seamless seams seamstress seamstress's seamstresses seaport seaport's seaports sear search searched searches searching searchlight searchlight's searchlights seared searing sears seas seashell seashell's seashells seashore seashore's seashores seasick seasickness seasickness's seaside seaside's seasides season season's seasonable seasonal seasoned seasoning seasoning's seasonings seasons seat seat's seated seating seating's seats seaweed seaweed's secede seceded secedes seceding secession secession's seclude secluded secludes secluding seclusion seclusion's second secondaries secondarily secondary seconded secondhand seconding secondly seconds secrecy secrecy's secret secretarial secretaries secretary secretary's secrete secreted secreter secretes secretest secreting secretion secretion's secretions secretive secretively secretly secrets secs sect sect's section section's sectioned sectioning sections sector sector's sectors sects secular secure secured securely securer secures securest securing securities security security's sedan sedan's sedans sedate sedated sedater sedates sedatest sedating sedation sedation's sedative sedatives sedentary sediment sediment's sedimentary sediments seduce seduced seduces seducing seduction seduction's seductions seductive see seed seed's seeded seedier seediest seeding seedless seedling seedling's seeds seedy seeing seeing's seek seeking seeks seem seemed seeming seemingly seems seen seep seepage seepage's seeped seeping seeps seer sees seesaw seesaw's seesawed seesawing seesaws seethe seethed seethes seething seethings segment segment's segmentation segmentation's segmented segmenting segments segregate segregated segregates segregating segregation segregation's seize seized seizes seizing seizure seizure's seizures seldom select selected selecting selection selection's selections selective selectively selector selector's selectors selects self self's selfish selfishly selfishness selfless sell seller seller's sellers selling sellout sellout's sellouts sells selves selves's semantic semantically semantics semantics's semblance semblance's semblances semen semen's semester semester's semesters semicircle semicircle's semicircles semicolon semicolon's semicolons semiconductor semiconductor's semiconductors semifinal semifinal's semifinalist semifinalist's semifinalists semifinals seminal seminar seminar's seminaries seminars seminary seminary's semiprecious senate senate's senates senator senator's senatorial senators send sender sender's sending sends senile senility senility's senior seniority seniority's seniors sensation sensation's sensational sensationalism sensationalism's sensationally sensations sense sense's sensed senseless senses sensibilities sensibility sensibility's sensible sensibler sensibles sensiblest sensibly sensing sensitive sensitively sensitives sensitivities sensitivity sensitivity's sensor sensor's sensors sensory sensual sensuality sensuality's sensuous sent sentence sentence's sentenced sentences sentencing sentience sentience's sentient sentiment sentiment's sentimental sentimentality sentimentality's sentiments sentries sentry sentry's separable separate separated separately separates separates's separating separation separation's separations separator separator's separators sepulchre sepulchre's sepulchred sepulchres sepulchring sequel sequel's sequels sequence sequence's sequenced sequencer sequencer's sequences sequencing sequential sequentially sequin sequin's sequining sequinned sequins sequoia sequoia's sequoias sera serenade serenade's serenaded serenades serenading serene serened serenely serener serenes serenest serening serenity serenity's sergeant sergeant's sergeants serial serial's serials series series's serious seriously seriousness seriousness's sermon sermon's sermoned sermoning sermons serpent serpent's serpented serpenting serpents serrated serum serum's serums servant servant's servanted servanting servants serve served server server's servers serves service service's serviceable serviced serviceman serviceman's servicemen services servicewoman servicewomen servicing serviette serviette's serviettes servile serviles serving serving's servings servitude servitude's session session's sessions set setback setbacks sets settable setter setter's setters setting setting's settings settle settled settlement settlement's settlements settler settler's settlers settles settling setup setup's setups seven seven's sevens seventeen seventeen's seventeens seventeenth seventeenths seventh sevenths seventies seventieth seventieths seventy seventy's sever several severance severance's severances severe severed severely severer severest severing severity severity's severs sew sewage sewage's sewed sewer sewer's sewers sewing sewing's sewn sews sex sex's sexed sexes sexier sexiest sexing sexism sexism's sexist sexist's sexists sexual sexuality sexuality's sexually sexy sh shabbier shabbiest shabbily shabby shack shack's shackle shackle's shackled shackles shackling shacks shade shade's shaded shades shadier shadiest shading shading's shadings shadow shadow's shadowed shadowier shadowiest shadowing shadows shadowy shady shaft shaft's shafted shafting shafts shaggier shaggiest shaggy shake shakedown shakedowns shaken shakes shakeup shakeups shakier shakiest shakily shaking shaking's shaky shall shallow shallower shallowest shallowness shallowness's shallows sham sham's shamble shambles shambles's shame shame's shamed shameful shamefully shameless shamelessly shames shaming shammed shamming shampoo shampoo's shampooed shampooing shampoos shamrock shamrock's shamrocks shams shanties shanty shanty's shantytown shantytown's shantytowns shape shape's shaped shapelier shapeliest shapely shapes shaping share share's shared shareholder shareholder's shareholders shares sharing shark shark's sharked sharking sharks sharp sharped sharpen sharpened sharpener sharpeners sharpening sharpens sharper sharper's sharpest sharping sharply sharpness sharpness's sharps shatter shattered shattering shatters shave shaved shaven shaver shaver's shavers shaves shaving shaving's shawl shawl's shawled shawling shawls she she'd she'll she's sheaf sheaf's shear sheared shearing shears sheath sheath's sheathe sheathed sheathes sheathing sheaths sheave sheaves sheaves's shed shed's shedding sheds sheen sheen's sheep sheep's sheepish sheepishly sheer sheered sheerer sheerest sheering sheers sheet sheet's sheets sheik sheik's sheikh sheikhs sheiks shelf shelf's shell shell's shelled sheller shellfish shellfish's shellfishes shelling shells shelter shelter's sheltered sheltering shelters shelve shelved shelves shelves's shelving shelving's shenanigan shenanigans shepherd shepherd's shepherded shepherding shepherds sherbet sherbet's sherbets sheriff sheriff's sheriffs sherries sherry sherry's shes shied shield shield's shielded shielding shields shies shift shifted shiftier shiftiest shifting shiftless shifts shifty shimmer shimmered shimmering shimmers shin shin's shine shined shines shingle shingle's shingled shingles shingling shinier shiniest shining shinned shinnied shinnies shinning shinny shinny's shinnying shins shiny ship ship's shipload shipload's shiploads shipment shipment's shipments shipped shipping shipping's ships shipshape shipwreck shipwreck's shipwrecked shipwrecking shipwrecks shipyard shipyard's shipyards shire shire's shirk shirked shirking shirks shirt shirt's shirted shirting shirts shirtsleeve shirtsleeve's shirtsleeves shit shits shittier shittiest shitting shitty shiver shivered shivering shivers shoal shoal's shoaled shoaling shoals shock shocked shocking shocks shod shodden shoddier shoddiest shoddily shoddy shoe shoe's shoed shoeing shoelace shoelace's shoelaces shoes shoestring shoestring's shoestrings shone shoo shooed shooing shook shook's shoon shoos shoot shooting shootings shoots shop shop's shopkeeper shopkeeper's shopkeepers shoplift shoplifted shoplifter shoplifter's shoplifters shoplifting shoplifting's shoplifts shopped shopper shopper's shoppers shopping shopping's shops shore shore's shored shores shoring shorn short shortage shortage's shortages shortchange shortchanged shortchanges shortchanging shortcoming shortcoming's shortcomings shortcut shortcut's shortcuts shortcutting shorted shorten shortened shortening shortening's shortenings shortens shorter shortest shortfall shortfall's shortfalls shorthand shorthand's shorting shortlist shortly shortness shortness's shorts shortsighted shortwave shortwave's shortwaves shot shot's shotgun shotgun's shotgunned shotgunning shotguns shots should shoulder shoulder's shouldered shouldering shoulders shouldest shouldn't shout shout's shouted shouting shouts shove shoved shovel shovel's shovelled shovelling shovels shoves shoving show showbiz showcase showcase's showcased showcases showcasing showdown showdown's showdowns showed shower shower's showered showering showers showier showiest showing showing's showings showman showman's showmanship showmanship's showmen shown showpiece showpiece's showpieces showroom showroom's showrooms shows showy shrank shrapnel shrapnel's shred shred's shredded shredding shreds shrew shrew's shrewd shrewder shrewdest shrewdly shrewdness shrewdness's shrewed shrewing shrews shriek shriek's shrieked shrieking shrieks shrill shrilled shriller shrillest shrilling shrills shrimp shrimp's shrimped shrimping shrimps shrine shrine's shrines shrink shrinkage shrinkage's shrinking shrinks shrivel shrivelled shrivelling shrivels shroud shroud's shrouded shrouding shrouds shrub shrub's shrubbed shrubberies shrubbery shrubbery's shrubbing shrubs shrug shrugged shrugging shrugs shrunk shrunken shuck shuck's shucked shucking shucks shuckses shudder shuddered shuddering shudders shuffle shuffled shuffles shuffling shun shunned shunning shuns shunt shunted shunting shunts shush shushed shushes shushing shut shutdown shutdown's shutdowns shuteye shuteye's shuts shutter shutter's shuttered shuttering shutters shutting shuttle shuttle's shuttled shuttles shuttling shy shyer shyest shying shyly shyness shyness's shyster shyster's shysters sibling sibling's siblings sic sices sick sicked sicken sickened sickening sickenings sickens sicker sickest sicking sickle sickle's sickled sickles sicklier sickliest sickling sickly sickness sickness's sicknesses sicks sics side side's sideburns sided sidekick sidekick's sidekicks sideline sideline's sidelined sidelines sidelining sidelong sides sideshow sideshow's sideshows sidestep sidestepped sidestepping sidesteps sidetrack sidetracked sidetracking sidetracks sidewalk sidewalk's sidewalks sideways siding siding's sidings sidle sidled sidles sidling siege siege's sieges sierra sierra's siesta siesta's siestas sieve sieve's sieved sieves sieving sift sifted sifting sifts sigh sighed sighing sighs sight sight's sighted sighting sightings sightless sightread sights sightseeing sightseer sightseers sigma sigma's sign sign's signal signal's signalled signalling signals signatories signatory signatory's signature signature's signatures signed signer significance significance's significant significantly signified signifies signify signifying signing signings signpost signpost's signposted signposting signposts signs silence silence's silenced silencer silencer's silencers silences silencing silent silenter silentest silently silents silhouette silhouette's silhouetted silhouettes silhouetting silicon silicon's silk silk's silken silkened silkening silkens silkier silkies silkiest silks silky sill sill's sillier sillies silliest silliness silliness's sills silly silo silo's silos silt silt's silted silting silts silver silver's silvered silverier silveriest silvering silvers silversmith silversmith's silversmiths silverware silverware's silvery similar similarities similarity similarity's similarly simile simile's similes simmer simmered simmering simmers simper simpered simpering simpers simple simpled simpler simples simplest simplex simplicity simplicity's simplification simplifications simplified simplifies simplify simplifying simpling simplistic simply simulate simulated simulates simulating simulation simulation's simulations simulator simulator's simulators simultaneous simultaneously sin sin's since sincere sincerely sincerer sincerest sincerity sincerity's sine sine's sinew sinew's sinews sinewy sinful sing singe singed singeing singer singer's singers singes singing single singled singles singling singly sings singsong singsong's singsonged singsonging singsongs singular singularity singularity's singularly singulars sinister sink sinking sinking's sinks sinned sinner sinner's sinners sinning sins sinus sinus's sinuses sip sipped sipping sips sir sir's sire sire's sired siren siren's sirens sires siring sirloin sirloin's sirloins sirred sirring sirs sissier sissies sissiest sissy sissy's sister sister's sistered sisterhood sisterhood's sisterhoods sistering sisterly sisters sit sitcom sitcom's sitcoms site site's sited sites siting sits sitter sitter's sitters sitting sitting's sittings situate situated situates situating situation situation's situations six six's sixes sixpence sixpence's sixpences sixteen sixteen's sixteens sixteenth sixteenths sixth sixths sixties sixtieth sixtieths sixty sixty's sizable size size's sizeable sized sizer sizes sizing sizzle sizzled sizzles sizzling skate skate's skateboard skateboard's skateboarded skateboarder skateboarders skateboarding skateboards skated skater skater's skaters skates skating skein skein's skeined skeining skeins skeleton skeleton's skeletons skeptically sketch sketch's sketched sketches sketchier sketchiest sketching sketchy skew skewed skewer skewer's skewered skewering skewers skewing skews ski ski's skid skidded skidding skids skied skier skiers skies skiing skiing's skill skill's skilled skillet skillet's skillets skillful skillfully skills skim skimmed skimming skimp skimped skimpier skimpiest skimping skimps skimpy skims skin skin's skinflint skinflint's skinflints skinhead skinhead's skinheads skinned skinnier skinniest skinning skinny skins skintight skip skipped skipper skipper's skippered skippering skippers skipping skips skirmish skirmish's skirmished skirmishes skirmishing skirt skirt's skirted skirting skirts skis skit skit's skited skiting skits skittish skulk skulked skulking skulks skull skull's skullcap skullcap's skullcaps skulls skunk skunk's skunked skunking skunks sky sky's skydive skydived skydiver skydiver's skydivers skydives skydiving skydiving's skydove skyed skying skylight skylight's skylights skyline skyline's skylines skyrocket skyrocket's skyrocketed skyrocketing skyrockets skyscraper skyscraper's skyscrapers slab slab's slabbed slabbing slabs slack slacked slacken slackened slackening slackens slacker slacker's slackers slackest slacking slacks slag slag's slain slake slaked slakes slaking slalom slalom's slalomed slaloming slaloms slam slammed slamming slams slander slander's slandered slandering slanders slang slang's slant slanted slanting slants slap slap's slapdash slapdashes slapped slapping slaps slapstick slapstick's slash slashed slashes slashing slat slat's slate slate's slated slates slather slather's slathered slathering slathers slating slats slaughter slaughter's slaughtered slaughterhouse slaughterhouse's slaughterhouses slaughtering slaughters slave slave's slaved slavery slavery's slaves slaving slavish slay slaying slayings slays sleazier sleaziest sleazy sled sled's sledded sledding sledgehammer sledgehammer's sledgehammered sledgehammering sledgehammers sleds sleek sleeked sleeker sleekest sleeking sleeks sleep sleep's sleeper sleeper's sleepers sleepier sleepiest sleepily sleeping sleeping's sleepless sleeplessness sleeplessness's sleeps sleepwalk sleepwalked sleepwalking sleepwalks sleepy sleepyhead sleepyhead's sleepyheads sleet sleet's sleeted sleeting sleets sleeve sleeve's sleeveless sleeves sleigh sleigh's sleighed sleighing sleighs slender slenderer slenderest slept sleuth sleuth's sleuths slew slewed slewing slews slice slice's sliced slices slicing slick slicked slicker slickest slicking slicks slid slide slided slides sliding slier sliest slight slighted slighter slightest slighting slightly slights slim slime slime's slimier slimiest slimmed slimmer slimmest slimming slims slimy sling sling's slinging slings slingshot slingshot's slingshots slink slinked slinking slinks slip slipped slipper slipper's slipperier slipperiest slippers slippery slipping slips slipshod slit slither slithered slithering slithers slits slitted slitter slitting sliver sliver's slivered slivering slivers slob slob's slobber slobbered slobbering slobbers slobs slog slogan slogan's slogans slogged slogging slogs slop slope sloped slopes sloping slopped sloppier sloppiest sloppily slopping sloppy slops slosh slosh's sloshed sloshes sloshing slot slot's sloth sloth's slothed slothful slothing sloths slots slotted slotting slouch slouched slouches slouching slovenlier slovenliest slovenly slow slowdown slowdown's slowdowns slowed slower slowest slowing slowly slowness slowness's slowpoke slowpoke's slowpokes slows sludge sludge's sludged sludges sludging slug slug's slugged slugging sluggish slugs sluice sluice's sluiced sluices sluicing slum slum's slumber slumbered slumbering slumbers slummed slummer slumming slump slumped slumping slumps slums slung slunk slur slurp slurped slurping slurps slurred slurring slurs slush slush's slushier slushiest slushy slut slut's sluts sly slyer slyest slyly slyness slyness's smack smack's smacked smacking smacks small smalled smaller smallest smalling smallish smallpox smallpox's smalls smart smarted smarter smartest smarting smartly smarts smash smashed smashes smashing smattering smattering's smatterings smear smeared smearing smears smell smelled smellier smelliest smelling smells smelly smelt smelted smelting smelts smidgen smidgen's smidgens smile smile's smiled smiles smiling smirk smirk's smirked smirking smirks smit smite smites smith smith's smithereens smiths smiting smitten smock smock's smocked smocking smocks smog smog's smoggier smoggiest smoggy smoke smoke's smoked smoker smoker's smokers smokes smokestack smokestack's smokestacks smokier smokies smokiest smoking smoking's smoky smoldered smolders smooch smooched smooches smooching smooth smoothed smoother smoothes smoothest smoothing smoothly smoothness smoothness's smooths smote smother smothered smothering smothers smoulder smouldered smouldering smoulders smudge smudged smudges smudging smug smugged smugger smuggest smugging smuggle smuggled smuggler smuggler's smugglers smuggles smuggling smugly smugness smugness's smugs smut smut's smuts smuttier smuttiest smutty smrgsbord smrgsbord's smrgsbords snack snack's snacked snacking snacks snafu snafu's snafus snag snag's snagged snagging snags snail snail's snailed snailing snails snake snake's snaked snakes snaking snap snapped snappier snappiest snapping snappy snaps snapshot snapshot's snapshots snare snare's snared snares snaring snarl snarled snarling snarls snatch snatched snatches snatching snazzier snazziest snazzy sneak sneaked sneaker sneaker's sneakers sneakier sneakiest sneaking sneaks sneaky sneer sneer's sneered sneering sneers sneeze sneezed sneezes sneezing snicker snicker's snickered snickering snickers snide snider snides snidest sniff sniffed sniffing sniffle sniffled sniffles sniffles's sniffling sniffs snigger snigger's snip snipe snipe's sniped sniper sniper's snipers snipes sniping snipped snippet snippet's snippets snipping snips snit snit's snitch snitched snitches snitching snits snob snob's snobbery snobbery's snobbier snobbiest snobbish snobby snobs snooker snooker's snoop snooped snooping snoops snootier snootiest snooty snooze snoozed snoozes snoozing snore snored snores snoring snorkel snorkel's snorkeled snorkeling snorkelled snorkelling snorkels snort snorted snorting snorts snot snot's snots snotted snottier snottiest snotting snotty snout snout's snouted snouting snouts snow snow's snowball snowball's snowballed snowballing snowballs snowboard snowboarded snowboarding snowboards snowbound snowdrift snowdrift's snowdrifts snowed snowfall snowfall's snowfalls snowflake snowflake's snowflakes snowier snowiest snowing snowman snowman's snowmen snowmobile snowmobile's snowmobiled snowmobiles snowmobiling snowplow snowplow's snowplowed snowplowing snowplows snows snowstorm snowstorm's snowstorms snowy snub snubbed snubbing snubs snuck snuff snuffed snuffer snuffing snuffs snug snugged snugger snuggest snugging snuggle snuggled snuggles snuggling snugly snugs so soak soaked soaking soakings soaks soap soap's soaped soapier soapiest soaping soaps soapy soar soared soaring soars sob sobbed sobbing sober sobered soberer soberest sobering sobers sobriety sobriety's sobs soccer soccer's sociable sociables social socialise socialised socialises socialising socialism socialism's socialist socialist's socialists socialite socialite's socialites socially socials societies society society's socioeconomic sociological sociological's sociologist sociologist's sociologists sociology sociology's sociopath sociopath's sociopaths sock sock's socked socket socket's sockets socking socks sod sod's soda soda's sodas sodded sodden sodding sodium sodium's sodomy sodomy's sods sofa sofa's sofas soft softball softball's softballs soften softened softening softens softer softest softhearted softie softies softly softness softness's software software's softy softy's soggier soggiest soggy soil soil's soiled soiling soils sojourn sojourn's sojourned sojourning sojourns solace solace's solaced solaces solacing solar sold solder solder's soldered soldering solders soldier soldier's soldiered soldiering soldiers sole soled solely solemn solemner solemnest solemnity solemnity's solemnly soles soli solicit solicited soliciting solicitor solicitor's solicitors solicitous solicits solid solidarity solidarity's solider solidest solidified solidifies solidify solidifying solidity solidly solids soliloquies soliloquy soliloquy's soling solitaire solitaire's solitaires solitaries solitary solitude solitude's solo solo's soloed soloing soloist soloist's soloists solos soluble solubles solution solution's solutions solvable solve solved solvent solvents solves solving somber sombrely some somebodies somebody someday somehow someone someones someplace somersault somersault's somersaulted somersaulting somersaults something somethings sometime sometimes someway someways somewhat somewhats somewhere somewheres son son's sonata sonata's sonatas song song's songs songwriter songwriter's songwriters sonic sonics sonnet sonnet's sonnets sonorous sons soon sooner soonest soot soot's soothe soothed soother soothes soothest soothing soothingly soothings sootier sootiest sooty sop sop's sophisticate sophisticated sophisticates sophisticating sophistication sophistication's sophistry sophistry's sophomore sophomore's sophomores sophomoric soporific soporifics sopped sopping soppings soprano soprano's sopranos sops sorbet sorbet's sorbets sorcerer sorcerer's sorcerers sorceress sorceresses sorcery sorcery's sordid sore sored sorely soreness sorer sores sorest soring sororities sorority sorority's sorrier sorriest sorrow sorrow's sorrowed sorrowful sorrowfully sorrowing sorrows sorry sort sort's sorta sorted sorting sorts souffl souffl's souffls sought soul soul's soulful souls sound sound's sounded sounder soundest sounding soundly soundness soundness's soundproof soundproofed soundproofing soundproofs sounds soundtrack soundtrack's soundtracks soup soup's souped souping soups sour source source's sourced sources sourcing sourdough sourdoughs soured sourer sourest souring sourly sourness sourness's sours south south's southbound southeast southeast's southeasterly southeastern southeastward southerlies southerly southern southerner southerner's southerners southerns southpaw southpaw's southpaws southward southwest southwest's southwesterly southwestern southwestward souvenir souvenir's souvenirs sovereign sovereign's sovereigns sovereignty sovereignty's sow sowed sowing sown sows sox sox's soybean soybean's soybeans spa spa's space space's spacecraft spacecraft's spacecrafts spaced spaces spaceship spaceship's spaceships spacey spacial spacier spaciest spacing spacing's spacious spaciousness spaciousness's spacy spade spade's spaded spades spading spaghetti spaghetti's span span's spangle spangle's spangled spangles spangling spaniel spaniel's spanielled spanielling spaniels spank spanked spanking spanking's spankings spanks spanned spanner spanner's spanners spanning spans spar spar's spare spared sparer spares sparest sparing sparingly spark spark's sparked sparking sparkle sparkled sparkler sparkler's sparklers sparkles sparkling sparks sparred sparrer sparring sparrow sparrow's sparrows spars sparse sparsely sparseness sparser sparsest spas spasm spasm's spasmed spasming spasmodic spasms spastic spastics spat spat's spate spate's spates spatial spats spatted spatter spattered spattering spatters spatting spatula spatula's spatulas spawn spawn's spawned spawning spawns spay spayed spaying spays speak speaker speaker's speakers speaking speaks spear spear's speared spearhead spearhead's spearheaded spearheading spearheads spearing spearmint spearmint's spears special specialer specialisation specialisation's specialisations specialise specialised specialises specialising specialist specialist's specialists specialities speciality speciality's specially specials species specific specifically specification specification's specifications specifics specified specifier specifier's specifies specify specifying specimen specimen's specimens specious speck speck's specked specking speckle speckled speckles speckling specks spectacle spectacle's spectacles spectacular spectacularly spectaculars spectator spectator's spectators spectra spectra's spectre spectre's spectres spectrum spectrum's spectrums speculate speculated speculates speculating speculation speculation's speculations speculative speculator speculator's speculators sped speech speech's speeched speeches speeching speechless speed speed's speedboat speedboat's speedboats speeded speedier speediest speedily speeding speedometer speedometer's speedometers speeds speedway speedway's speedways speedy spell spellbind spellbinding spellbinds spellbound speller speller's spelling spelling's spellings spells spelt spend spending spends spendthrift spendthrift's spendthrifts spent sperm sperm's sperms spew spewed spewing spews sphere sphere's spheres spherical sphinges sphinx sphinx's sphinxes spice spice's spiced spices spicier spiciest spicing spicy spider spider's spiders spied spiel spiel's spieled spieling spiels spies spiffied spiffier spiffies spiffiest spiffy spiffying spigot spigot's spigots spike spike's spiked spikes spiking spill spilling spills spilt spin spinach spinach's spinal spinals spindlier spindliest spindly spine spine's spineless spines spinning spinning's spins spinster spinster's spinsters spiral spiralled spiralling spirals spire spire's spires spirit spirit's spirited spiriting spirits spiritual spiritually spirituals spit spite spite's spited spiteful spitefuller spitefullest spites spiting spits spitted spitting spittle spittle's splash splashed splashes splashier splashiest splashing splashy splat splat's splats splatted splatter splattered splattering splatters splatting splay splayed splaying splays spleen spleen's spleens splendid splendider splendidest splendidly splendour splendour's splice spliced splices splicing splint splint's splinted splinter splinter's splintered splintering splinters splinting splints split splits splits's splitting splittings splurge splurge's splurged splurges splurging spoil spoiling spoils spoilsport spoilsport's spoilsports spoilt spoke spoken spokes spokesman spokesman's spokesmen spokespeople spokesperson spokespersons spokeswoman spokeswoman's spokeswomen sponge sponge's sponged sponges spongier spongiest sponging spongy sponsor sponsor's sponsored sponsoring sponsors sponsorship spontaneity spontaneity's spontaneous spontaneously spoof spoof's spoofed spoofing spoofs spook spook's spooked spookier spookiest spooking spooks spooky spool spool's spooled spooling spools spoon spoon's spooned spoonful spoonful's spoonfuls spooning spoons spoonsful sporadic sporadically spore spores sporran sporran's sport sport's sported sportier sportiest sporting sports sportscast sportscast's sportscasting sportscasts sportsman sportsman's sportsmanship sportsmanship's sportsmen sportswear sportswear's sporty spot spot's spotless spotlight spotlight's spotlighted spotlighting spotlights spots spotted spottier spottiest spotting spotting's spotty spouse spouse's spouses spout spouted spouting spouts sprain sprained spraining sprains sprang sprangs sprawl sprawled sprawling sprawls spray spray's sprayed spraying sprays spread spreading spreads spreadsheet spreadsheets spree spree's spreed spreeing sprees sprier spriest sprig sprig's sprigs spring springboard springboard's springboards springier springiest springing springing's springs springtime springtime's springy sprinkle sprinkled sprinkler sprinkler's sprinklers sprinkles sprinkling sprinkling's sprinklings sprint sprint's sprinted sprinter sprinters sprinting sprints sprout sprouted sprouting sprouts spruce spruce's spruced sprucer spruces sprucest sprucing sprung spry spryer spryest spud spud's spuds spun spunk spunk's spunked spunkier spunkies spunkiest spunking spunks spunky spur spur's spurious spurn spurned spurning spurns spurred spurring spurs spurt spurted spurting spurts sputter sputtered sputtering sputters spy spy's spying squabble squabbled squabbles squabbling squad squad's squadded squadding squadron squadron's squadrons squads squalid squalider squalidest squall squall's squalled squalling squalls squalor squalor's squander squandered squandering squanders square square's squared squarely squarer squares squarest squaring squash squashed squashes squashing squat squats squatted squatter squatter's squattered squattering squatters squattest squatting squawk squawk's squawked squawking squawks squeak squeak's squeaked squeakier squeakiest squeaking squeaks squeaky squeal squeal's squealed squealing squeals squeamish squeeze squeezed squeezes squeezing squelch squelched squelches squelching squid squid's squidded squidding squids squint squinted squinter squintest squinting squints squire squire's squired squires squiring squirm squirmed squirming squirms squirrel squirrel's squirrelled squirrelling squirrels squirt squirted squirting squirts stab stabbed stabbing stabbings stabilise stabilised stabilises stabilising stability stability's stable stable's stabled stabler stables stablest stabling stabs stack stack's stacked stacking stacks stadia stadia's stadium stadium's stadiums staff staff's staffed staffer staffer's staffers staffing staffs stag stag's stage stage's stagecoach stagecoach's stagecoaches staged stages stagger staggered staggering staggeringly staggerings staggers staging staging's stagings stagnant stagnate stagnated stagnates stagnating stagnation stagnation's stags staid staider staidest stain stained staining stains stair stair's staircase staircase's staircases stairs stairway stairway's stairways stake stake's staked stakeout stakeout's stakeouts stakes staking stale staled stalemate stalemate's stalemated stalemates stalemating staler stales stalest staling stalk stalk's stalked stalker stalker's stalkers stalking stalkings stalks stall stall's stalled stalling stallion stallion's stallions stalls stalwart stalwarts stamina stamina's stammer stammered stammering stammers stamp stamped stampede stampede's stampeded stampedes stampeding stamping stamps stance stance's stances stanch stanched stancher stanches stanchest stanching stand standard standard's standardisation standardisation's standardise standardised standardises standardising standards standby standbys standing standing's standings standoff standoff's standoffs standout standout's standouts standpoint standpoint's standpoints stands standstill standstill's standstills stank stanks stanza stanza's stanzas staple staple's stapled stapler stapler's staplers staples stapling star star's starboard starboard's starch starch's starched starches starchier starchiest starching starchy stardom stardom's stare stared stares starfish starfish's starfishes staring stark starked starker starkest starking starks starlight starlight's starred starrier starriest starring starry stars start started starter starter's starters starting startle startled startles startling startlingly starts starvation starvation's starve starved starves starving starvings stash stashed stashes stashing state state's stated statelier stateliest stately statement statement's statements stater states statesman statesman's statesmanlike statesmanship statesmanship's statesmen statewide static stating station station's stationary stationed stationery stationery's stationing stations statistic statistic's statistical statistically statistician statistician's statisticians statistics stats statue statue's statues stature stature's statures status status's statuses statute statute's statutes statutory staunch staunched stauncher staunches staunchest staunching staunchly stave stave's staved staves staving stay stayed staying stays steadfast steadied steadier steadies steadiest steadily steady steadying steak steak's steaks steal stealing stealing's steals stealth stealth's stealthier stealthiest stealthily stealthy steam steam's steamboat steamboat's steamboats steamed steamier steamies steamiest steaming steamroll steamrolled steamroller steamroller's steamrollered steamrollering steamrollers steamrolling steamrolls steams steamy steel steel's steeled steeling steels steep steeped steeper steepest steeping steeple steeple's steeples steeply steepness steeps steer steered steering steers stellar stem stem's stemmed stemming stems stench stench's stenched stenches stenching stencil stencil's stencilled stencilling stencils stenographer stenographer's stenographers stenography stenography's step step's stepbrother stepbrother's stepbrothers stepchild stepchild's stepchildren stepdaughter stepdaughter's stepdaughters stepfather stepfather's stepfathers stepladder stepladder's stepladders stepmother stepmother's stepmothers stepped stepping steps stepsister stepsister's stepsisters stepson stepson's stepsons stereo stereos stereotype stereotype's stereotyped stereotypes stereotypical stereotyping sterile sterilisation sterilisation's sterilise sterilised sterilises sterilising sterility sterility's sterling sterling's stern sterned sterner sternest sterning sternly sternness sterns steroid steroid's steroids stethoscope stethoscope's stethoscopes stew stew's steward steward's stewarded stewardess stewardess's stewardesses stewarding stewards stewed stewing stews stick stick's sticker sticker's stickers stickied stickier stickies stickiest sticking stickler stickler's sticklers sticks sticky stickying stiff stiffed stiffen stiffened stiffening stiffens stiffer stiffest stiffing stiffly stiffness stiffness's stiffs stifle stifled stifles stifling stiflings stigma stigma's stigmas stigmata stigmatise stigmatised stigmatises stigmatising still stillbirth stillbirth's stillbirths stillborn stillborns stilled stiller stillest stilling stillness stillness's stills stilt stilt's stilted stilts stimulant stimulant's stimulants stimulate stimulated stimulates stimulating stimulation stimulation's stimuli stimuli's stimulus stimulus's sting stinger stinger's stingers stingier stingiest stinginess stinginess's stinging stings stingy stink stinker stinker's stinkers stinking stinkings stinks stint stinted stinting stints stipend stipend's stipends stipulate stipulated stipulates stipulating stipulation stipulation's stipulations stir stirred stirring stirrup stirrup's stirrups stirs stitch stitch's stitched stitches stitching stitching's stock stock's stockade stockade's stockaded stockades stockading stockbroker stockbroker's stockbrokers stocked stockholder stockholder's stockholders stockier stockiest stocking stocking's stockings stockpile stockpiled stockpiles stockpiling stocks stocky stockyard stockyard's stockyards stodgier stodgiest stodgy stoic stoic's stoical stoicism stoicism's stoics stoke stoked stokes stoking stole stolen stoles stolid stolider stolidest stolidly stomach stomach's stomachache stomachache's stomachaches stomached stomaching stomachs stomp stomped stomping stomps stone stone's stoned stones stonewall stonewalled stonewalling stonewalls stoney stonier stoniest stoning stony stood stool stool's stools stoop stooped stooping stoops stop stopgap stopgap's stopgaps stoplight stoplight's stoplights stopover stopover's stopovers stoppage stoppage's stoppages stopped stopper stopper's stoppered stoppering stoppers stopping stopping's stops stops's stopwatch stopwatch's stopwatches storage storage's store store's stored storehouse storehouse's storehouses storekeeper storekeeper's storekeepers storeroom storeroom's storerooms stores storey storey's storeys stories storing stork stork's storks storm storm's stormed stormier stormiest storming storms stormy story story's storyteller storyteller's storytellers stout stouter stoutest stove stove's stoves stow stowaway stowaway's stowaways stowed stowing stows straddle straddled straddles straddling straggle straggled straggler stragglers straggles straggling straight straighted straighten straightened straightening straightens straighter straightest straightforward straightforwardly straightforwards straighting straights strain strained strainer strainer's strainers straining strains strait strait's straited straiting straitjacket straitjacket's straitjacketed straitjacketing straitjackets straits strand stranded stranding strands strange strangely strangeness strangeness's stranger stranger's strangered strangering strangers strangest strangle strangled stranglehold stranglehold's strangleholds strangles strangling strangulation strangulation's strap strap's strapless straplesses strapped strapping straps strata strata's stratagem stratagem's stratagems strategic strategically strategics strategies strategy strategy's stratified stratifies stratify stratifying stratosphere stratosphere's stratospheres stratum stratum's stratums straw straw's strawberries strawberry strawberry's strawed strawing straws stray strayed straying strays streak streak's streaked streakier streakiest streaking streaks streaky stream stream's streamed streamer streamer's streamers streaming streaming's streamline streamline's streamlined streamlines streamlining streams street street's streetcar streetcar's streetcars streetlight streetlight's streetlights streets strength strength's strengthen strengthened strengthening strengthens strengths strenuous strenuously stress stress's stressed stresses stressful stressing stretch stretched stretcher stretcher's stretchers stretches stretching strew strewed strewing strewn strews stricken strict stricter strictest strictly strictness stridden stride stride's strident strides striding strife strife's strike striker striker's strikers strikes striking strikingly strikings string string's stringent stringier stringiest stringing strings stringy strip stripe stripe's striped stripes striping stripped stripper stripper's strippers stripping strips stript striptease striptease's stripteased stripteases stripteasing strive strived striven strives striving strode stroke stroke's stroked strokes stroking stroll strolled stroller stroller's strollers strolling strolls strong stronger strongest stronghold stronghold's strongholds strongly strove struck structural structuralist structuralist's structure structure's structured structures structuring struggle struggled struggles struggling strum strummed strumming strums strung strut struts strutted strutting stub stub's stubbed stubbier stubbies stubbiest stubbing stubble stubble's stubborn stubborned stubborner stubbornest stubborning stubbornly stubbornness stubbornness's stubborns stubby stubs stuck stud stud's studded studding student student's students studentship studentship's studied studies studio studio's studios studious studs study studying stuff stuffed stuffier stuffiest stuffing stuffing's stuffs stuffy stumble stumbled stumbles stumbling stump stump's stumped stumping stumps stun stung stunk stunned stunning stuns stunt stunted stunting stunts stupefied stupefies stupefy stupefying stupendous stupid stupider stupidest stupidities stupidity stupidity's stupidly stupids stupor stupor's stupors sturdier sturdiest sturdiness sturdiness's sturdy stutter stuttered stuttering stutters style style's styled styles styling stylish stylistic stylus stylus's stymie stymied stymieing stymies stymy stymying suave suaver suavest sub sub's subbed subbing subcommittee subcommittees subconscious subconsciously subculture subculture's subcultures subdivide subdivided subdivides subdividing subdivision subdivision's subdivisions subdue subdued subdues subduing subgroup subgroup's subject subject's subjected subjecting subjective subjectively subjectives subjects subjugate subjugated subjugates subjugating subjunctive subjunctives sublet sublets subletting sublime sublimed sublimer sublimes sublimest subliminal subliming submarine submarine's submarines submerge submerged submerges submerging submersion submersion's submission submission's submissions submissive submit submits submitted submitting subnormal subordinate subordinated subordinates subordinating subordination subordination's subpoena subpoena's subpoenaed subpoenaing subpoenas subprogram subroutine subroutine's subroutines subs subscribe subscribed subscriber subscriber's subscribers subscribes subscribing subscript subscription subscription's subscriptions subscripts subsection subsection's subsections subsequent subsequently subsequents subservience subservience's subservient subservients subset subset's subsets subside subsided subsides subsidiaries subsidiary subsidies subsiding subsidise subsidised subsidises subsidising subsidy subsidy's subsist subsisted subsistence subsistence's subsisting subsists substance substance's substances substandard substantial substantially substantiate substantiated substantiates substantiating substitute substituted substitutes substituting substitution substitution's substitutions subsystem subterfuge subterfuge's subterfuges subterranean subtitle subtitles subtle subtler subtlest subtleties subtlety subtlety's subtly subtract subtracted subtracting subtraction subtraction's subtractions subtracts suburb suburb's suburban suburbans suburbia suburbia's suburbs subversive subversives subvert subverted subverting subverts subway subway's subways succeed succeeded succeeding succeeds success success's successes successful successfully succession succession's successions successive successively successor successor's successors succinct succincter succinctest succinctly succour succour's succoured succouring succours succulent succulents succumb succumbed succumbing succumbs such suck sucked sucker sucker's suckered suckering suckers sucking suckle suckled suckles suckling sucks suction suction's suctioned suctioning suctions sudden suddenly suddenness suddenness's suds sue sued suede suede's sues suffer suffered sufferer sufferer's sufferers suffering suffering's sufferings suffers suffice sufficed suffices sufficiency sufficiency's sufficient sufficiently sufficing suffix suffix's suffixed suffixes suffixing suffocate suffocated suffocates suffocating suffocatings suffocation suffrage suffrage's sugar sugar's sugared sugarier sugariest sugaring sugars sugary suggest suggested suggester suggester's suggestible suggesting suggestion suggestion's suggestions suggestive suggestively suggests suicidal suicide suicide's suicides suing suit suit's suitability suitable suitably suitcase suitcase's suitcases suite suite's suited suites suiting suitor suitor's suitors suits sulk sulked sulkier sulkies sulkiest sulking sulks sulky sullen sullener sullenest sullenly sulphur sulphur's sultan sultan's sultans sultrier sultriest sultry sum sum's summaries summarily summarise summarised summarises summarising summary summary's summed summer summer's summered summerier summeriest summering summers summertime summertime's summery summing summit summit's summits summon summoned summoning summons summons's summonsed summonses summonsing sumptuous sums sun sun's sunbathe sunbathed sunbathes sunbathing sunbathing's sunblock sunblocks sunburn sunburn's sunburned sunburning sunburns sunburnt sundae sundae's sundaes sundial sundial's sundials sundown sundown's sundowns sundries sundry sunflower sunflower's sunflowers sung sunglasses sunk sunken sunks sunlight sunlight's sunlit sunned sunnier sunnies sunniest sunning sunny sunrise sunrise's sunrises sunrising suns sunscreen sunscreens sunset sunset's sunsets sunsetting sunshine sunshine's suntan suntan's suntanned suntanning suntans sunup sunup's sup super superb superber superbest superbly supercomputer supercomputers supered superficial superficially superficials superfluous superhighway superhighway's superhighways superhuman superimpose superimposed superimposes superimposing supering superintendent superintendent's superintendents superior superiority superiority's superiors superlative superlatives supermarket supermarket's supermarkets supernatural supernaturals superpower superpower's superpowers supers superscript superscripts supersede superseded supersedes superseding supersonic supersonics superstar superstar's superstars superstition superstition's superstitions superstitious superstructure superstructure's superstructures supervise supervised supervises supervising supervision supervision's supervisions supervisor supervisor's supervisors supervisory supper supper's suppers supplant supplanted supplanting supplants supple supplement supplement's supplemental supplementary supplemented supplementing supplements suppler supplest supplied supplier supplier's suppliers supplies supply supplying support supported supporter supporter's supporters supporting supportive supports suppose supposed supposedly supposes supposing supposings supposition supposition's suppositions suppress suppressed suppresses suppressing suppression suppression's supremacy supremacy's supreme supremely supremer supremest surcharge surcharge's surcharged surcharges surcharging sure surefire surely surer sures surest surf surf's surface surface's surfaced surfaces surfacing surfboard surfboard's surfboarded surfboarding surfboards surfed surfer surfer's surfers surfing surfing's surfs surge surge's surged surgeon surgeon's surgeons surgeries surgery surgery's surges surgical surgically surging surlier surliest surly surmise surmised surmises surmising surmount surmounted surmounting surmounts surname surname's surnames surpass surpassed surpasses surpassing surplus surplus's surplused surpluses surplusing surplussed surplussing surprise surprised surprises surprising surprisingly surprisings surreal surrealistic surreals surrender surrendered surrendering surrenders surreptitious surrogate surrogate's surrogates surround surrounded surrounding surrounding's surroundings surrounds surveillance surveillance's survey surveyed surveying surveyor surveyor's surveyors surveys survival survival's survivals survive survived survives surviving survivor survivor's survivors susceptible suspect suspected suspecting suspects suspend suspended suspender suspenders suspending suspends suspense suspense's suspension suspension's suspensions suspicion suspicion's suspicions suspicious suspiciously sustain sustainable sustained sustaining sustains sustenance sustenance's swab swab's swabbed swabbing swabs swagger swaggered swaggerer swaggering swaggers swallow swallowed swallowing swallows swam swamp swamp's swamped swampier swampiest swamping swamps swampy swan swan's swank swanked swanker swankest swanking swanks swans swap swapped swapping swaps swarm swarm's swarmed swarming swarms swarthier swarthiest swarthy swat swatch swatch's swatches swathe swathed swathes swathing swats swatted swatting sway swayed swaying sways swear swearing swears sweat sweat's sweated sweater sweater's sweaters sweatier sweatiest sweating sweatpants sweats sweatshirt sweatshirts sweatshop sweatshop's sweatshops sweaty sweep sweeper sweeper's sweepers sweeping sweepings sweeps sweeps's sweepstake sweepstakes sweet sweeten sweetened sweetener sweetener's sweeteners sweetening sweetens sweeter sweetest sweetheart sweetheart's sweethearts sweetie sweetie's sweeties sweetly sweetness sweetness's sweets swell swelled sweller swellest swelling swelling's swellings swells swelter sweltered sweltering swelterings swelters swept swerve swerved swerves swerving swift swifted swifter swiftest swifting swiftly swifts swig swig's swigged swigging swigs swill swilled swilling swills swim swimmer swimmers swimming swimming's swims swimsuit swimsuit's swimsuits swindle swindled swindler swindler's swindlers swindles swindling swine swine's swines swing swinging swings swipe swiped swipes swiping swirl swirled swirling swirls swish swished swisher swishes swishest swishing switch switch's switchable switchboard switchboard's switchboards switched switcher switches switching swivel swivel's swivelled swivelling swivels swollen swoon swooned swooning swoons swoop swooped swooping swoops sword sword's sworded swordfish swordfish's swordfishes swording swords swore sworn swum swung sycamore sycamore's sycamores sycophant sycophant's sycophants syllabi syllabi's syllable syllable's syllables syllabus syllabus's syllabuses symbol symbol's symbolic symbolically symbolics symbolise symbolised symbolises symbolising symbolism symbolism's symbols symmetric symmetrical symmetrically symmetry symmetry's sympathetic sympathetically sympathetics sympathies sympathise sympathised sympathiser sympathiser's sympathisers sympathises sympathising sympathy sympathy's symphonic symphonies symphony symphony's symptom symptom's symptomatic symptoms synagogue synagogue's synagogues synapse synapses sync synced synchronisation synchronisation's synchronise synchronised synchronises synchronising synchronous syncing syncs syndicate syndicate's syndicated syndicates syndicating syndication syndrome syndrome's syndromes synod synod's synods synonym synonym's synonymous synonyms synopses synopsis synopsis's synopsised synopsises synopsising syntactic syntactically syntax syntax's syntheses synthesis synthesis's synthesise synthesised synthesiser synthesiser's synthesisers synthesises synthesising synthetic synthetically synthetics syphilis syphilis's syphilised syphilises syphilising syphon syphon's syphoned syphoning syphons syringe syringe's syringed syringes syringing syrup syrup's system system's systematic systematically systematics systems t tab tab's tabbed tabbies tabbing tabby tabernacle tabernacle's tabernacles table table's tablecloth tablecloth's tablecloths tabled tables tablespoon tablespoon's tablespoonful tablespoonful's tablespoonfuls tablespoons tablespoonsful tablet tablet's tablets tabling tabloid tabloid's tabloids taboo tabooed tabooing taboos tabs tabulate tabulated tabulates tabulating tabulation tabulation's taces tacit tacitly taciturn tack tack's tacked tackier tackies tackiest tackiness tackiness's tacking tackle tackle's tackled tackles tackling tackling's tacks tacky taco taco's tacos tact tact's tactful tactfully tactic tactic's tactical tactically tactics tactless tactlessly tad tad's tadpole tadpole's tadpoles tads taffies taffy taffy's tag tag's tagged tagging tags tail tail's tailed tailgate tailgate's tailgated tailgates tailgating tailing taillight taillight's taillights tailor tailor's tailored tailoring tailors tailpipe tailpipe's tailpipes tails tailspin tailspin's tailspins taint tainted tainting taints take taken takeoff takeoff's takeoffs takeout takeouts takeover takeover's takeovers taker takers takes taking takings talc talc's tale tale's talent talent's talented talented's talents tales talisman talisman's talismans talk talkative talked talker talker's talkers talking talks tall taller tallest tallied tallies tallow tallow's tally tallying talon talon's talons tambourine tambourine's tambourines tame tamed tamely tameness tamer tames tamest taming tamper tampered tampering tampers tampon tampon's tampons tan tan's tandem tandem's tandems tang tang's tangent tangent's tangential tangents tangerine tangerine's tangerines tangible tangibles tangier tangies tangiest tangle tangle's tangled tangles tangling tango tango's tangoed tangoing tangos tangs tangy tank tank's tankard tankard's tankards tanked tanker tanker's tankers tanking tanks tanned tanner tannest tanning tans tantalise tantalised tantalises tantalising tantalisingly tantamount tantrum tantrum's tantrums tap tap's tape tape's taped taper tapered tapering tapers tapes tapestries tapestry tapestry's tapeworm tapeworm's tapeworms taping tapped tapping tapping's taps taps's tar tar's tarantula tarantula's tarantulae tarantulas tardier tardies tardiest tardiness tardy target target's targeted targeting targets tariff tariff's tariffs tarmac tarmacked tarmacking tarmacs tarnish tarnished tarnishes tarnishing tarot tarot's tarots tarp tarp's tarpaulin tarpaulin's tarpaulins tarps tarred tarried tarrier tarries tarriest tarring tarry tarrying tars tart tart's tartan tartan's tartans tartar tartar's tartars tarted tarter tartest tarting tarts task task's tasked tasking tasks tassel tassel's tasselled tasselling tassells taste taste's tasted tasteful tastefully tasteless taster taster's tasters tastes tastier tastiest tasting tasty tatter tattered tattered's tattering tatters tattle tattled tattles tattletale tattletale's tattletales tattling tattoo tattoo's tattooed tattooing tattoos tatty taught taunt taunted taunting taunts taut tauted tauter tautest tauting tautly tautology tautology's tauts tavern tavern's taverns tawdrier tawdriest tawdry tawnier tawniest tawny tawny's tax tax's taxable taxation taxation's taxed taxes taxi taxi's taxicab taxicab's taxicabs taxidermy taxidermy's taxied taxies taxiing taxing taxings taxis taxpayer taxpayer's taxpayers taxying tea tea's teach teacher teacher's teachers teaches teaching teaching's teachings teacup teacup's teacups teaed teaing teak teak's teakettle teakettle's teakettles teaks team team's teamed teaming teammate teammate's teammates teams teamster teamster's teamsters teamwork teamwork's teapot teapot's teapots tear tear's teardrop teardrop's teardrops teared tearful teargas teargases teargassed teargasses teargassing tearing tears teas tease teased teases teasing teaspoon teaspoon's teaspoonful teaspoonful's teaspoonfuls teaspoons teaspoonsful teat teat's teats technical technicalities technicality technicality's technically technicals technician technician's technicians technique technique's techniques technological technologically technologies technologist technologist's technologists technology technology's tedious tediously tedium tedium's tee tee's teed teeing teem teemed teeming teems teen teenage teenaged teenager teenager's teenagers teens tees teeter teetered teetering teeters teeth teeth's teethe teethed teethes teething teething's teetotal teetotaller teetotaller's teetotallers telecommunications telecommute telecommuted telecommuter telecommuters telecommutes telecommuting telegram telegram's telegrams telegraph telegraph's telegraphed telegraphing telegraphs telepathic telepathy telepathy's telephone telephone's telephoned telephones telephoning telescope telescope's telescoped telescopes telescopic telescoping telethon telethon's telethons teletype televise televised televises televising television television's televisions tell teller teller's tellered tellering tellers telling tells telltale telltale's telltales temp temp's temped temper temper's temperament temperament's temperamental temperaments temperance temperance's temperate temperated temperates temperating temperature temperature's temperatures tempered tempering tempers tempest tempest's tempests tempestuous tempi temping template template's templates temple temple's temples tempo tempo's temporal temporaries temporarily temporary tempos temps tempt temptation temptation's temptations tempted tempting temptings tempts ten ten's tenable tenacious tenacity tenancies tenancy tenancy's tenant tenant's tenanted tenanting tenants tend tended tendencies tendency tendency's tender tendered tenderer tenderest tenderhearted tendering tenderise tenderised tenderises tenderising tenderly tenderness tenderness's tenders tending tendon tendon's tendons tendril tendril's tendrils tends tenement tenement's tenements tenet tenet's tenets tennis tennis's tenor tenor's tenors tens tense tensed tenser tenses tensest tensing tension tension's tensions tensors tent tent's tentacle tentacle's tentacles tentative tentatively tentatives tented tenth tenths tenting tents tenuous tenure tenure's tenured tenures tenuring tepee tepee's tepees tepid tequila tequila's tequilas term term's termed terminal terminally terminals terminate terminated terminates terminating termination termination's terminations terminator terminator's terminators terming termini terminologies terminology terminology's terminus terminus's terminuses termite termite's termites termly terms terrace terrace's terraced terraces terracing terrain terrain's terrains terrestrial terrestrials terrible terribly terrier terrier's terriers terrific terrified terrifies terrify terrifying territorial territorials territories territory territory's terror terror's terrorise terrorised terrorises terrorising terrorism terrorism's terrorist terrorist's terrorists terrors terse tersely terseness terseness's terser tersest test testable testament testament's testaments tested tester testers testes testes's testicle testicle's testicles testier testiest testified testifies testify testifying testimonial testimonial's testimonials testimonies testimony testimony's testing testis tests testy tetanus tetanus's tether tether's tethered tethering tethers text text's textbook textbook's textbooks textile textile's textiles texts textual textually texture texture's textures than thank thanked thankful thankfuller thankfullest thankfully thanking thankless thanks that that's thatch thatch's thatched thatcher thatches thatching thaw thawed thawing thaws the theatre theatre's theatres theatrical thee theft theft's thefts their theirs theist theists them thematic thematics theme theme's themes themselves then thence theologian theologian's theologians theological theologies theology theology's theorem theorem's theorems theoretic theoretical theoretically theoretician theoretician's theoreticians theories theorise theorised theorises theorising theorist theorist's theorists theory theory's therapeutic therapies therapist therapist's therapists therapy therapy's there there's thereabout thereabouts thereafter thereby therefore therein thereof thereon thereupon thermal thermals thermodynamics thermodynamics's thermometer thermometer's thermometers thermonuclear thermostat thermostat's thermostats thesauri thesaurus thesaurus's thesauruses these theses thesis thesis's theta theta's they they'd they'll they're they've thick thicken thickened thickening thickens thicker thickest thicket thicket's thickets thickly thickness thickness's thicknesses thief thief's thieve thieves thigh thigh's thighs thimble thimble's thimbled thimbles thimbling thin thing thing's thingamajig thingamajigs things think thinker thinker's thinkers thinking thinking's thinks thinly thinned thinner thinner's thinnest thinning thins third thirded thirding thirds thirst thirst's thirsted thirstier thirstiest thirstily thirsting thirsts thirsty thirteen thirteen's thirteens thirteenth thirteenths thirties thirtieth thirtieths thirty thirty's this thistle thistle's thistles thong thong's thongs thorn thorn's thornier thorniest thorns thorny thorough thoroughbred thoroughbreds thorougher thoroughest thoroughfare thoroughfare's thoroughfares thoroughly thoroughness thoroughness's those thou though thought thoughtful thoughtfully thoughtfulness thoughtless thoughtlessly thoughtlessness thoughtlessness's thoughts thous thousand thousand's thousands thousandth thousandths thrash thrashed thrashes thrashing thrashing's thrashings thread thread's threadbare threaded threading threads threat threat's threaten threatened threatening threateningly threatenings threatens threats three three's threes thresh threshed thresher thresher's threshers threshes threshing threshold threshold's thresholds threw thrice thrift thrift's thriftier thriftiest thrifts thrifty thrill thrill's thrilled thriller thriller's thrillers thrilling thrills thrive thrived thriven thrives thriving thrivings throat throat's throatier throatiest throats throaty throb throbbed throbbing throbs throne throne's thrones throng throng's thronged thronging throngs throttle throttle's throttled throttles throttling through throughout throughput throughput's throve throw throwaway throwaway's throwaways throwback throwback's throwbacks throwing thrown throws thrust thrusting thrusts thud thud's thudded thudding thuds thug thug's thugs thumb thumb's thumbed thumbing thumbnail thumbnail's thumbnails thumbs thumbtack thumbtack's thumbtacks thump thump's thumped thumping thumps thunder thunder's thunderbolt thunderbolt's thunderbolts thundered thundering thunderous thunders thunderstorm thunderstorm's thunderstorms thunderstruck thus thwart thwarted thwarting thwarts thy thyme thyme's thyroid thyroids tiara tiara's tiaras tic tic's ticced ticcing tick tick's ticked ticket ticket's ticketed ticketing tickets ticking ticking's tickle tickled tickles tickling ticklish ticks tics tidal tidbit tidbit's tidbits tide tided tides tidied tidier tidies tidiest tiding tidy tidying tidying's tie tiebreaker tiebreaker's tiebreakers tied tieing tier tier's tiers ties tiff tiff's tiffed tiffing tiffs tiger tiger's tigers tight tighten tightened tightening tightens tighter tightest tightfisted tightly tightness tightness's tightrope tightrope's tightropes tights tightwad tightwad's tightwads tilde tilde's tile tile's tiled tiles tiling till tilled tilling tills tilt tilted tilting tilts timber timber's timbers time time's timed timekeeper timekeeper's timekeepers timeless timelier timeliest timely timer timer's timers times timescale timescales timetable timetable's timetabled timetables timetabling timezone timid timider timidest timidity timidity's timidly timing timing's timings tin tin's tinder tinder's tinderbox tinderbox's tinderboxes tinfoil tinfoil's ting tinge tinged tingeing tinges tinging tingle tingled tingles tingling tings tinier tiniest tinker tinker's tinkered tinkering tinkers tinkle tinkled tinkles tinkling tinned tinnier tinnies tinniest tinning tinny tins tinsel tinsel's tinselled tinselling tinsels tint tint's tinted tinting tints tiny tip tipped tipping tips tipsier tipsiest tipsy tiptoe tiptoed tiptoeing tiptoes tirade tirade's tirades tire tire's tired tireder tiredest tiredness tireless tires tiresome tiring tirings tissue tissue's tissues tit tit's titillate titillated titillates titillating title title's titled titles titling tits titted titter tittered tittering titters titting tizzies tizzy tizzy's to toad toad's toads toadstool toadstool's toadstools toast toast's toasted toaster toaster's toasters toastier toasties toastiest toasting toasts toasty tobacco tobacco's tobaccoes tobacconist tobacconist's tobacconists tobaccos toboggan toboggan's tobogganed tobogganing toboggans today today's toddle toddled toddler toddler's toddlers toddles toddling toe toe's toed toehold toehold's toeholds toeing toenail toenail's toenails toes toffee toffee's toffees tofu tog toga toga's togae togas together togetherness togetherness's toggle toggle's toggled toggles toggling togs toil toil's toiled toilet toilet's toileted toileting toiletries toiletry toilets toiling toils token token's tokenism tokenism's tokens told tolerable tolerably tolerance tolerance's tolerances tolerant tolerate tolerated tolerates tolerating toll tollbooth tollbooth's tollbooths tolled tollgate tollgate's tollgates tolling tolls tomahawk tomahawk's tomahawked tomahawking tomahawks tomato tomato's tomatoes tomb tomb's tombed tombing tomboy tomboy's tomboys tombs tombstone tombstone's tombstones tomcat tomcat's tomcats tome tome's tomes tomfooleries tomfoolery tomfoolery's tomorrow tomorrow's tomorrows ton ton's tonal tone tone's toned tones tong tongs tongue tongue's tongued tongues tonguing tonic tonic's tonics tonight tonight's toning tonnage tonnage's tonnages tonne tonnes tons tonsil tonsil's tonsillitis tonsillitis's tonsils too took tool tool's toolbar toolbars tooled tooling toolkit tools toot tooted tooth tooth's toothache toothache's toothaches toothbrush toothbrush's toothbrushes toothpaste toothpaste's toothpastes toothpick toothpick's toothpicks tooting toots top top's topaz topaz's topazes topic topic's topical topics topless topographer topographer's topographers topographies topography topography's topology topology's topped topping topping's toppings topple toppled topples toppling tops torch torch's torched torches torching tore torment tormented tormenting tormentor tormentor's tormentors torments torn tornado tornado's tornadoes tornados torpedo torpedo's torpedoed torpedoes torpedoing torpedos torque torque's torrent torrent's torrential torrents torrid torrider torridest torsi torso torso's torsoes torsos tort tort's tortilla tortilla's tortillas tortoise tortoise's tortoises torts tortuous torture tortured torturer torturers tortures torturing toss tossed tosses tossing tost tot tot's total total's totalitarian totalitarianism totalitarianism's totalitarians totalities totality totality's totalled totalling totally totals tote toted totem totem's totems totes toting tots totted totter tottered tottering totters totting toucan toucan's toucans touch touchdown touchdown's touchdowns touched touches touchier touchiest touching touchings touchstone touchstone's touchstones touchy tough toughed toughen toughened toughening toughens tougher toughest toughing toughness toughness's toughs toupee toupee's toupees tour tour's toured touring tourism tourism's tourist tourist's tourists tournament tournament's tournaments tourniquet tourniquet's tourniquets tours tousle tousled tousles tousling tout touted touting touts tow toward towards towed towel towel's towelled towelling towellings towels tower tower's towered towering towers towing town town's townhouse townhouses towns township township's townships townspeople townspeople's tows toxic toxicity toxicity's toxicology toxicology's toxin toxin's toxins toy toy's toyed toying toys trace trace's traced tracer tracer's tracers traces tracing tracing's track track's tracked tracking tracks tract tract's traction traction's tractor tractor's tractors tracts trade trade's traded trademark trademark's trademarked trademarking trademarks trader trader's traders trades trading tradition tradition's traditional traditionalist traditionalist's traditionalists traditionally traditions traffic traffic's trafficked trafficking traffics tragedies tragedy tragedy's tragic tragically tragics trail trailblazer trailblazer's trailblazers trailed trailer trailer's trailered trailering trailers trailing trails train trained trainee trainee's trainees trainer trainer's trainers training training's trains trait trait's traitor traitor's traitorous traitors traits trajectories trajectory trajectory's tramp tramped tramping trample trampled tramples trampling trampoline trampoline's trampolined trampolines trampolining tramps trance trance's trances tranquil tranquiler tranquilest tranquilise tranquilised tranquiliser tranquiliser's tranquilisers tranquilises tranquilising tranquility tranquiller tranquillest tranquillity transact transacted transacting transaction transaction's transactions transacts transatlantic transcend transcended transcendence transcendence's transcendental transcending transcends transcontinental transcribe transcribed transcribes transcribing transcript transcript's transcription transcription's transcriptions transcripts transfer transferable transferred transferring transfers transform transformation transformation's transformations transformed transformer transformer's transformers transforming transforms transfusion transfusion's transfusions transgress transgressed transgresses transgressing transgression transgression's transgressions transient transients transistor transistor's transistors transit transit's transited transiting transition transition's transitional transitioned transitioning transitions transitive transitives transitory transits transitted transitting translate translated translates translating translation translation's translations translator translator's translators transliteration translucence translucence's translucent transmission transmission's transmissions transmit transmits transmitted transmitter transmitter's transmitters transmitting transparencies transparency transparency's transparent transparently transpire transpired transpires transpiring transplant transplanted transplanting transplants transport transportable transportation transportation's transported transporting transports transpose transposed transposes transposing transsexual transsexual's transsexuals transverse transversed transverses transversing transvestite transvestite's transvestites trap trap's trapdoor trapeze trapeze's trapezed trapezes trapezing trapezoid trapezoid's trapezoids trapped trapper trapper's trappers trapping trappings traps trash trash's trashcan trashcan's trashed trashes trashier trashiest trashing trashy trauma trauma's traumas traumata traumatic traumatise traumatised traumatises traumatising travel travelled traveller traveller's travellers travelling travellings travels traverse traversed traverses traversing travestied travesties travesty travesty's travestying trawl trawl's trawled trawler trawler's trawlers trawling trawls tray tray's trays treacheries treacherous treachery treachery's treacle treacle's tread treading treadmill treadmill's treadmills treads treason treason's treasure treasure's treasured treasurer treasurer's treasurers treasures treasuries treasuring treasury treasury's treat treat's treatable treated treaties treating treatise treatise's treatises treatment treatment's treatments treats treaty treaty's treble trebled trebles trebling tree tree's treed treeing trees treetop treetop's treetops trek trekked trekking treks trellis trellis's trellised trellises trellising tremble trembled trembles trembling tremendous tremendously tremor tremor's tremors trench trench's trenchant trenched trenches trenching trend trend's trended trendier trendies trendiest trending trends trendy trepidation trepidation's trespass trespassed trespasser trespasser's trespassers trespasses trespassing trestle trestle's trestles trial trial's trialled trialling trials triangle triangle's triangles triangular tribal tribe tribe's tribes tribulation tribulation's tribulations tribunal tribunal's tribunals tributaries tributary tributary's tribute tribute's tributes triceps triceps's tricepses trick trick's tricked trickery trickery's trickier trickiest tricking trickle trickled trickles trickling tricks trickster trickster's tricksters tricky tricycle tricycle's tricycled tricycles tricycling trident trident's tridents tried tries trifle trifle's trifled trifles trifling trigger trigger's triggered triggering triggers trigonometry trigonometry's trike trike's triked trikes triking trill trill's trilled trilling trillion trillion's trillions trills trilogies trilogy trilogy's trim trimester trimester's trimesters trimmed trimmer trimmest trimming trimmings trims trinity trinity's trinket trinket's trinkets trio trio's trios trip trip's tripe tripe's triple tripled triples triplet triplet's triplets triplicate triplicated triplicates triplicating tripling tripod tripod's tripods tripos tripos's tripped tripping trips trite triter trites tritest triumph triumph's triumphant triumphantly triumphed triumphing triumphs trivia trivial trivialise trivialised trivialises trivialising triviality triviality's trivially trod trodden trodes troll trolled trolley trolley's trolleys trolling trolls trombone trombone's trombones tromp tromped tromping tromps troop troop's trooped trooper trooper's troopers trooping troops trophied trophies trophy trophy's trophying tropic tropic's tropical tropicals tropics trot trots trotted trotting troubadour troubadour's troubadours trouble trouble's troubled troublemaker troublemaker's troublemakers troubles troubleshoot troubleshooted troubleshooter troubleshooter's troubleshooters troubleshooting troubleshoots troubleshot troublesome troubling trough trough's troughs trounce trounced trounces trouncing troupe troupe's trouped troupes trouping trouser trouser's trousers trout trout's trouts trowel trowel's trowelled trowelling trowels truancy truancy's truant truant's truanted truanting truants truce truce's truces truck truck's trucked trucker trucker's truckers trucking trucking's truckload truckload's truckloads trucks truculent trudge trudged trudges trudging true trued trueing truer trues truest truffle truffle's truffles truing truism truism's truisms truly trump trump's trumped trumpet trumpet's trumpeted trumpeter trumpeter's trumpeters trumpeting trumpets trumping trumps truncate truncated truncates truncating truncation truncation's trundle trundled trundles trundling trunk trunk's trunked trunking trunks trust trust's trusted trustee trustee's trustees trustful trustier trusties trustiest trusting trusts trustworthier trustworthiest trustworthy trusty trusty's truth truth's truthful truthfully truthfulness truths try trying tryings tryout tryout's tryouts ts tsar tsar's tsars tub tub's tuba tuba's tubae tubas tubbier tubbiest tubby tube tube's tubed tuberculosis tuberculosis's tubes tubing tubing's tubs tubular tuck tucked tucking tucks tuft tuft's tufted tufting tufts tug tugboat tugboat's tugboats tugged tugging tugs tuition tuition's tulip tulip's tulips tumble tumbled tumbler tumbler's tumblers tumbles tumbling tummies tummy tummy's tumour tumour's tumours tumult tumult's tumulted tumulting tumults tumultuous tuna tuna's tunas tundra tundra's tundras tune tune's tuned tuneful tuner tuner's tuners tunes tunic tunic's tunics tuning tuning's tunnel tunnel's tunnelled tunnelling tunnellings tunnels turban turban's turbans turbine turbine's turbines turbulence turbulence's turbulent turd turd's turds tureen tureen's tureens turf turf's turfed turfing turfs turgid turkey turkey's turkeys turmoil turmoil's turmoiled turmoiling turmoils turn turnaround turnaround's turnarounds turncoat turncoat's turncoats turned turner turner's turning turning's turnip turnip's turniped turniping turnips turnout turnout's turnouts turnover turnover's turnovers turnpike turnpike's turnpikes turnround turns turnstile turnstile's turnstiles turntable turntable's turntables turpentine turpentine's turquoise turquoise's turquoises turret turret's turrets turtle turtle's turtleneck turtleneck's turtlenecks turtles turves tush tushed tushes tushing tusk tusk's tusks tussle tussled tussles tussling tutor tutor's tutored tutorial tutorial's tutorials tutoring tutors tux tuxedo tuxedo's tuxedoes tuxedos tuxes twang twang's twanged twanging twangs tweak tweaked tweaking tweaks twee tweed tweed's tweet tweeted tweeting tweets tweezers twelfth twelfths twelve twelve's twelves twenties twentieth twentieths twenty twenty's twerp twerp's twerps twice twiddle twiddled twiddles twiddling twig twig's twigged twigging twigs twilight twilight's twin twine twine's twined twines twinge twinge's twinged twingeing twinges twinging twining twinkle twinkled twinkles twinkling twinned twinning twins twirl twirled twirling twirls twist twisted twister twister's twisters twisting twists twit twitch twitched twitches twitching twits twitted twitter twittered twittering twitters twitting two two's twos tycoon tycoon's tycoons tying tyke tyke's tykes type type's typecast typecasting typecasts typed typeface typeface's typefaces types typescript typescript's typeset typesets typesetter typesetter's typesetting typesetting's typewrite typewriter typewriter's typewriters typewrites typewriting typewritten typewrote typhoid typhoid's typhoon typhoon's typhoons typhus typhus's typical typically typified typifies typify typifying typing typist typist's typists typo typo's typographic typographical typos tyrannical tyrannies tyrannise tyrannised tyrannises tyrannising tyranny tyranny's tyrant tyrant's tyrants tyre tyre's tyred tyres tyring u ubiquitous ubiquity udder udder's udders ugh uglied uglier uglies ugliest ugliness ugliness's ugly uglying uh ulcer ulcer's ulcered ulcering ulcers ulterior ultimata ultimate ultimated ultimately ultimates ultimating ultimatum ultimatum's ultimatums ultra ultrasonic ultrasonics ultrasound ultrasound's ultrasounds ultraviolet ultraviolet's um umbrella umbrella's umbrellaed umbrellaing umbrellas umpire umpire's umpired umpires umpiring umpteen umpteenth unabashed unabated unable unabridged unabridgeds unacceptable unacceptably unaccepted unaccompanied unaccountable unaccountably unadulterated unaffected unaided unaltered unambiguous unambiguously unanimity unanimity's unanimous unanimously unanswerable unanswered unarmed unassigned unassuming unattached unattainable unattended unattractive unauthorised unavailable unavoidable unavoidably unaware unawares unbalanced unbearable unbearably unbeatable unbeaten unbecoming unbelievable unbelievably unbeliever unbelievers unbiased unbiassed unblock unblocked unblocking unblocks unborn unbounded unbreakable unbridled unbroken unburden unburdened unburdening unburdens unbutton unbuttoned unbuttoning unbuttons uncannier uncanniest uncannily uncanny unceasing uncertain uncertainly uncertainties uncertainty uncertainty's unchallenged unchanged uncharacteristic uncharacteristically uncharitable uncharted unchecked unchristian uncle uncle's unclean uncleaner uncleanest unclear unclearer unclearest uncled uncles uncling uncomfortable uncomfortably uncommon uncommoner uncommonest uncommonly uncompromising unconcerned unconditional unconditionally unconfirmed unconnected unconscionable unconscious unconsciously unconsciousness unconsciousness's unconstitutional uncontrollable uncontrollably uncontrolled uncontroversial unconventional unconvinced unconvincing uncountable uncouth uncover uncovered uncovering uncovers uncultured uncut undamaged undaunted undecidable undecided undecideds undefined undemocratic undeniable undeniably under underage underbrush underbrush's underbrushed underbrushes underbrushing underclass underclassman underclassmen undercover undercurrent undercurrent's undercurrents undercut undercuts undercutting underdog underdog's underdogs underestimate underestimated underestimates underestimating underflow underflow's underfoot undergarment undergarment's undergarments undergo undergoes undergoing undergone undergrad undergrad's undergrads undergraduate undergraduate's undergraduates underground underground's undergrounds undergrowth undergrowth's underhanded underlain underlay underlays underlie underlies underline underlined underlines underlining underlying undermine undermined undermines undermining underneath underneaths undernourished underpaid underpants underpass underpass's underpasses underpay underpaying underpays underprivileged underrate underrated underrates underrating underscore underscored underscores underscoring undershirt undershirt's undershirts underside underside's undersides understaffed understand understandable understandably understanding understanding's understandings understands understate understated understatement understatement's understatements understates understating understood understudied understudies understudy understudying undertake undertaken undertaker undertaker's undertakers undertakes undertaking undertaking's undertakings undertone undertone's undertones undertook undertow undertow's undertows underwater underwear underwear's underweight underwent underworld underworld's underworlds underwrite underwrites underwriting underwritten underwrote undeserved undesirable undesirables undetected undetermined undeveloped undid undisclosed undisturbed undo undocumented undoes undoing undoing's undoings undone undoubted undoubtedly undress undressed undresses undressing undue unduly undying unearth unearthed unearthing unearthly unearths unease unease's uneasier uneasiest uneasily uneasiness uneasiness's uneasy uneconomic uneconomical uneducated unemployable unemployed unemployment unemployment's unending unenlightened unequal unequalled unequally unequals unequivocal unerring unethical uneven unevener unevenest unevenly uneventful unexpected unexpectedly unexplained unfailing unfair unfairer unfairest unfairly unfairness unfaithful unfamiliar unfashionable unfasten unfastened unfastening unfastens unfavourable unfeasible unfeeling unfilled unfinished unfit unfits unfitted unfitting unfold unfolded unfolding unfolds unforeseen unforgettable unforgivable unfortunate unfortunately unfortunates unfounded unfriendlier unfriendliest unfriendly unfunny unfurl unfurled unfurling unfurls ungainlier ungainliest ungainly ungodlier ungodliest ungodly ungrammatical ungrateful ungratefully unhappier unhappiest unhappily unhappiness unhappiness's unhappy unhealthier unhealthiest unhealthy unheard unhelpful unholier unholiest unholy unhook unhooked unhooking unhooks unicorn unicorn's unicorns unicycle unicycle's unidentified unification unification's unified unifies uniform uniform's uniformed uniformer uniformest uniforming uniformity uniformity's uniformly uniforms unify unifying unilateral unilaterally unimaginative unimportant unimpressed uninformative uninformed uninhabitable uninhibited uninitiated uninspired uninspiring uninsured unintelligent unintelligible unintended unintentional unintentionally uninterested uninteresting union union's unionise unionised unionises unionising unions unique uniquely uniqueness uniquer uniquest unisex unison unison's unit unit's unite united unites unities uniting units unity unity's universal universally universals universe universe's universes universities university university's unjust unjustifiable unjustified unjustly unkempt unkind unkinder unkindest unkindlier unkindliest unkindly unkindness unknowingly unknown unknowns unlabelled unlawful unleaded unleash unleashed unleashes unleashing unless unlike unlikelier unlikeliest unlikely unlikes unlimited unlisted unload unloaded unloading unloads unlock unlocked unlocking unlocks unluckier unluckiest unlucky unman unmanned unmanning unmans unmarked unmarried unmask unmasked unmasking unmasks unmistakable unmistakably unmitigated unmodified unmoved unnamed unnatural unnaturally unnecessarily unnecessary unnerve unnerved unnerves unnerving unnoticed unobtainable unobtrusive unoccupied unofficial unofficially unoriginal unorthodox unpack unpacked unpacking unpacks unpaid unparallelled unpick unpleasant unpleasantly unpleasantness unpleasantness's unplug unplugged unplugging unplugs unpopular unpopularity unpopularity's unprecedented unpredictable unprepared unprincipled unprintable unprivileged unproductive unprofessional unprofitable unprotected unproven unprovoked unpublished unqualified unquestionable unquestionably unquestioned unravel unravelled unravelling unravels unread unreadable unreal unrealistic unreasonable unreasonably unrecognised unrelated unrelenting unreliability unreliability's unreliable unremarkable unrepeatable unrepresentative unreserved unreservedly unresolved unresponsive unrest unrest's unrested unresting unrestrained unrestricted unrests unrivalled unroll unrolled unrolling unrolls unruffled unrulier unruliest unruliness unruliness's unruly unsafe unsafer unsafest unsaid unsanitary unsatisfactory unsatisfied unsavoury unsay unsaying unsays unscathed unscheduled unscientific unscrew unscrewed unscrewing unscrews unscrupulous unseasonable unseat unseated unseating unseats unseemlier unseemliest unseemly unseen unseens unset unsettle unsettled unsettles unsettling unsightlier unsightliest unsightly unsigned unskilled unsolicited unsolved unsophisticated unsound unsounder unsoundest unspeakable unspecified unspoken unsportsmanlike unstable unstabler unstablest unsteadier unsteadiest unsteady unstoppable unstructured unstuck unsubstantiated unsuccessful unsuccessfully unsuitable unsuited unsung unsupportable unsupported unsure unsuspecting untangle untangled untangles untangling untenable unthinkable unthinking unthinkingly untidier untidiest untidy untie untied unties until untiled untiles untiling untilled untimelier untimeliest untimely untiring unto untold untouchable untouchables untouched untoward untrained untried untrue untruer untruest untrustworthy untruthful untying unusable unused unusual unusually unveil unveiled unveiling unveils unwanted unwarranted unwary unwashed unwelcome unwell unwell's unwieldier unwieldiest unwieldy unwilling unwillingness unwind unwinding unwinds unwise unwiser unwisest unwitting unwittingly unworkable unworthy unwound unwrap unwrapped unwrapping unwraps unwritten unyielding unzip unzipped unzipping unzips up upbeat upbeat's upbeats upbringing upbringing's upbringings upchuck upchucked upchucking upchucks upcoming update updated updates updating upend upended upending upends upfront upgrade upgraded upgrades upgrading upheaval upheaval's upheavals upheld uphill uphills uphold upholding upholds upholster upholstered upholsterer upholsterer's upholsterers upholstering upholsters upholstery upholstery's upkeep upkeep's uplift uplifted uplifting upliftings uplifts upload upon upped upper uppercase upperclassman upperclassman's upperclassmen uppermost uppers upping uppity upright uprights uprising uprising's uprisings uproar uproar's uproars uproot uprooted uprooting uproots ups upscale upset upsets upsetting upsetting's upshot upshot's upshots upside upside's upstage upstaged upstages upstaging upstairs upstanding upstart upstart's upstarted upstarting upstarts upstate upstream upstreamed upstreaming upstreams upsurge upsurged upsurges upsurging upswing upswing's upswings uptake uptake's uptakes uptight uptown upturn upturned upturning upturns upward upwardly upwards uranium uranium's urban urbane urbaner urbanest urchin urchin's urchins urge urged urgency urgency's urgent urgently urges urging urinate urinated urinates urinating urine urine's urn urn's urned urning urns us usable usage usage's usages use used useful usefully usefulness usefulness's useless uselessly uselessness uselessness's user user's users uses usher usher's ushered ushering ushers using usual usually usurp usurped usurping usurps utensil utensil's utensils uteri uterus uterus's uteruses utilisation utilisation's utilise utilised utilises utilising utilitarian utilitarianism utilitarianism's utilities utility utility's utmost utopia utopian utopians utopias utter utterance utterance's utterances uttered utterer utterest uttering utterly utters v vacancies vacancy vacancy's vacant vacantly vacate vacated vacates vacating vacation vacation's vacationed vacationer vacationers vacationing vacations vaccinate vaccinated vaccinates vaccinating vaccination vaccination's vaccinations vaccine vaccine's vaccines vacillate vacillated vacillates vacillating vacua vacuous vacuum vacuum's vacuumed vacuuming vacuums vagabond vagabond's vagabonded vagabonding vagabonds vagaries vagary vagina vagina's vaginae vaginal vaginas vagrant vagrant's vagrants vague vagued vagueing vaguely vagueness vagueness's vaguer vagues vaguest vain vainer vainest vainly valedictorian valedictorian's valedictorians valentine valentine's valentines valet valet's valeted valeting valets valiant valiantly valid validate validated validates validating validation validation's validity validity's validly valise valise's valises valley valley's valleys valour valour's valuable valuables value value's valued valueless values valuing valve valve's valved valves valving vampire vampire's vampired vampires vampiring van van's vandal vandal's vandalise vandalised vandalises vandalising vandalism vandalism's vandals vane vane's vanes vanguard vanguard's vanguards vanilla vanilla's vanillas vanish vanished vanishes vanishing vanishings vanities vanity vanity's vanned vanning vanquish vanquished vanquishes vanquishing vans vapour vapour's vapourise vapourised vapourises vapourising vapours variability variability's variable variables variance variance's variances variant variants variation variation's variations varied varies varieties variety variety's various variously varnish varnish's varnished varnishes varnishing varsities varsity varsity's vary varying vase vase's vasectomies vasectomy vasectomy's vases vast vaster vastest vastly vastness vastness's vasts vat vat's vats vatted vatting vault vault's vaulted vaulting vaults veal veal's vealed vealing veals vector vector's vectors veer veered veering veers vegan vegan's vegans vegetable vegetable's vegetables vegetarian vegetarian's vegetarianism vegetarianism's vegetarians vegetation vegetation's veggie veggies vehement vehemently vehicle vehicle's vehicles vehicular veil veil's veiled veiling veils vein vein's veined veining veins velocities velocity velocity's velour velour's velvet velvet's velveted velvetier velvetiest velveting velvets velvety vend vended vendetta vendetta's vendettas vending vendor vendor's vendors vends veneer veneer's veneered veneering veneers venerable venerate venerated venerates venerating veneration veneration's vengeance vengeance's vengeful venison venison's venom venom's venomous vent vent's vented ventilate ventilated ventilates ventilating ventilation ventilation's ventilator ventilator's ventilators venting ventricle ventricle's ventricles ventriloquism ventriloquism's ventriloquist ventriloquist's ventriloquists vents venture ventured ventures venturing venue venue's venues veracity veracity's veranda veranda's verandas verb verb's verbal verballed verballing verbally verbals verbatim verbiage verbiage's verbose verbosity verbosity's verbs verdict verdict's verdicts verge verge's verged verges verging verier veriest verification verified verifies verify verifying veritable vermin vermin's vernacular vernaculars versatile versatility versatility's verse verse's versed verses versing version version's versions versus vertebra vertebra's vertebrae vertebras vertebrate vertebrate's vertebrates vertical vertically verticals vertices vertices's vertigo vertigo's verve verve's very vessel vessel's vessels vest vest's vested vestibule vestibule's vestibules vestige vestige's vestiges vesting vestment vestment's vestments vests vet vet's veteran veteran's veterans veterinarian veterinarian's veterinarians veterinaries veterinary veto veto's vetoed vetoes vetoing vets vetted vetting vex vexation vexation's vexations vexed vexes vexing via viability viability's viable viaduct viaduct's viaducts vial vial's vials vibe vibes vibrant vibrate vibrated vibrates vibrating vibration vibration's vibrations vicar vicar's vicarious vicariously vicars vice vice's viced vices vicing vicinity vicinity's vicious viciously victim victim's victimisation victimisation's victimise victimised victimises victimising victims victor victor's victories victorious victors victory victory's video video's videocassette videocassettes videoed videoing videos videotape videotaped videotapes videotaping vie vied vies view view's viewed viewer viewer's viewers viewing viewing's viewings viewpoint viewpoint's viewpoints views vigil vigil's vigilance vigilance's vigilant vigilante vigilante's vigilantes vigils vigorous vigorously vigour vigour's vile viler vilest vilified vilifies vilify vilifying villa villa's villae village village's villager villager's villagers villages villain villain's villainies villainous villains villainy villainy's villas vindicate vindicated vindicates vindicating vindication vindication's vindications vindictive vine vine's vined vinegar vinegar's vines vineyard vineyard's vineyards vining vintage vintage's vintages vinyl vinyl's vinyls viola viola's violas violate violated violates violating violation violations violence violence's violent violently violet violet's violets violin violin's violinist violinist's violinists violins viper viper's vipers viral virgin virgin's virginity virginity's virgins virile virility virility's virtual virtually virtue virtue's virtues virtuosi virtuoso virtuoso's virtuosos virtuous virtuously virulent virus virus's viruses visa visa's visaed visage visage's visages visaing visas viscosity viscosity's viscous vise vise's vised vises visibility visibility's visible visibly vising vision vision's visionaries visionary visioned visioning visions visit visitation visitation's visitations visited visiting visitor visitor's visitors visits visor visor's visors vista vista's vistaed vistaing vistas visual visualise visualised visualises visualising visually visuals vital vitality vitality's vitally vitals vitamin vitamin's vitamins vitriolic vivacious vivaciously vivacity vivacity's vivid vivider vividest vividly vivisection vivisection's vocabularies vocabulary vocabulary's vocal vocalist vocalist's vocalists vocals vocation vocation's vocational vocations vociferous vociferously vodka vodka's vogue vogue's vogued vogueing vogues voguing voice voice's voiced voices voicing void voided voiding voids volatile volatility volatility's volcanic volcanics volcano volcano's volcanoes volcanos voled voling volition volition's volley volley's volleyball volleyball's volleyballs volleyed volleying volleys volt volt's voltage voltage's voltages volts volume volume's volumed volumes voluming voluminous voluntaries voluntarily voluntary volunteer volunteer's volunteered volunteering volunteers voluptuous vomit vomited vomiting vomits voodoo voodoo's voodooed voodooing voodoos voracious voracity voracity's vortex vortex's vortexes vortices vortices's vote vote's voted voter voter's voters votes voting vouch vouched voucher voucher's vouchers vouches vouching vow vow's vowed vowel vowel's vowels vowing vows voyage voyage's voyaged voyager voyager's voyagers voyages voyaging voyeur voyeur's voyeurism voyeurism's voyeurs vs vulgar vulgarer vulgarest vulgarities vulgarity vulgarity's vulnerabilities vulnerability vulnerable vulture vulture's vultures vying w wackier wackiest wacky wad wad's wadded wadding waddle waddled waddles waddling wade waded wades wading wads wafer wafer's wafers waffle waffle's waffled waffles waffling waft wafted wafting wafts wag wage wage's waged wager wager's wagered wagering wagers wages wagged wagging waggon waggon's waggons waging wags waif waif's waifed waifing waifs wail wailed wailing wails waist waist's waistband waistband's waistbands waisted waisting waistline waistline's waistlines waists wait waited waiter waiter's waiters waiting waitress waitress's waitresses waits waive waived waiver waiver's waivers waives waiving wake wake's waked waken waken's wakened wakening wakens wakes waking walk walked walker walker's walkers walking walkout walkout's walkouts walks wall wall's walled wallet wallet's wallets walling wallop walloped walloping wallops wallow wallowed wallowing wallows wallpaper wallpaper's wallpapered wallpapering wallpapers walls walnut walnut's walnuts walrus walrus's walruses waltz waltz's waltzed waltzes waltzing wan wand wand's wander wandered wanderer wanderer's wanderers wandering wanders wands wane waned wanes waning wanna wannabe wannabes wanner wannest want wanted wanting wantings wanton wantoned wantoner wantoning wantons wants war warble warbled warbles warbling ward ward's warded warden warden's wardened wardening wardens warding wardrobe wardrobe's wardrobes wards ware ware's warehouse warehouse's warehoused warehouses warehousing wares warfare warfare's warhead warhead's warheads warier wariest warily warlike warlock warlock's warlocks warlord warlord's warlords warm warmed warmer warmer's warmest warming warmly warmonger warmonger's warmongering warmongering's warmongers warms warmth warmth's warn warned warning warning's warnings warns warp warpath warpath's warpaths warped warping warps warrant warrant's warranted warrantied warranties warranting warrants warranty warranty's warrantying warred warren warren's warrens warring warring's warrior warrior's warriors wars warship warship's warships wart wart's wartime wartime's warts wary was wases wash washable washables washbasin washbasin's washbasins washcloth washcloth's washcloths washed washer washer's washered washering washers washes washing washing's washout washout's washouts washroom washroom's washrooms wasn't wasp wasp's wasps wastage wastage's waste wastebasket wastebasket's wastebaskets wasted wasteful wastefully wasteland wasteland's wastelands wastes wasting watch watchdog watchdog's watchdogs watched watches watchful watching watchmaker watchmaker's watchmakers watchman watchman's watchmen watchword watchword's watchwords water water's waterbed waterbeds watercolour watercolour's watercolours watered waterfall waterfall's waterfalls waterfront waterfront's waterfronts waterier wateriest watering watering's waterlogged watermark watermark's watermarked watermarking watermarks watermelon watermelon's watermelons waterproof waterproofed waterproofing waterproofs waters watershed watershed's watersheds watertight waterway waterway's waterways waterworks waterworks's watery watt watt's watter wattest watts wave waved waveform waveform's wavelength wavelength's wavelengths waver wavered wavering wavers waves wavier waviest waving wavy wax wax's waxed waxes waxier waxiest waxiness waxiness's waxing waxy way way's waylaid waylay waylaying waylays ways wayside wayside's waysides wayward we we'd we'll we're we've weak weaken weakened weakening weakens weaker weakest weaklier weakliest weakling weakling's weakly weakness weakness's weaknesses wealth wealth's wealthier wealthiest wealthy wean weaned weaning weans weapon weapon's weaponry weaponry's weapons wear wearied wearier wearies weariest wearily weariness weariness's wearing wearisome wears weary wearying weasel weasel's weaselled weaselling weasels weather weather's weathered weathering weathers weave weaved weaver weaver's weavers weaves weaving web web's webbed webbing webs website websites wed wedded wedder wedding wedding's weddings wedge wedge's wedged wedges wedging wedlock wedlock's weds wee weed weed's weeded weedier weediest weeding weeds weedy weeing week week's weekday weekday's weekdays weekend weekend's weekended weekending weekends weeklies weekly weeknight weeknight's weeknights weeks weep weeping weeps weer wees weest weigh weighed weighing weighs weight weight's weighted weightier weightiest weighting weighting's weightless weightlessness weightlessness's weightlifter weightlifters weightlifting weightlifting's weights weighty weird weirded weirder weirdest weirding weirdness weirdness's weirdo weirdo's weirdos weirds welcome welcomed welcomes welcoming weld welded welder welder's welders welding welds welfare welfare's well welled welling wellington wells welsh welshed welshes welshing welt welt's welted welter weltered weltering welters welting welts went wept were weren't werewolf werewolf's werewolves west west's westbound wested westerlies westerly western westerner westerner's westerners westernise westernised westernises westernising westerns westing wests westward westwards wet wetback wetback's wetbacks wets wetted wetter wettest wetting whack whacked whacking whacks whale whale's whaled whaler whaler's whalers whales whaling whaling's wham wham's whammed whamming whams wharf wharf's wharves what what's whatchamacallit whatchamacallits whatever whats whatsoever wheat wheat's wheedle wheedled wheedles wheedling wheel wheel's wheelbarrow wheelbarrow's wheelbarrows wheelchair wheelchair's wheelchairs wheeled wheeling wheels wheeze wheezed wheezes wheezing when whence whenever whens where whereabouts whereas whereby wherein wheres whereupon wherever wherewithal wherewithal's whet whether whets whetted whetting whew whewed whewing whews which whichever whiff whiff's whiffed whiffing whiffs while whiled whiles whiling whilst whim whim's whimmed whimming whimper whimpered whimpering whimpers whims whimsical whine whine's whined whiner whiners whines whining whinnied whinnier whinnies whinniest whinny whinnying whip whiplash whiplash's whiplashes whipped whipping whipping's whippings whips whips's whir whirl whirled whirling whirlpool whirlpool's whirlpools whirls whirlwind whirlwind's whirlwinds whirr whirred whirring whirrs whirs whisk whisked whisker whisker's whiskered whiskers whiskey whiskey's whiskeys whiskies whisking whisks whisky whisky's whiskys whisper whispered whispering whispers whistle whistled whistles whistling whistling's white whiten whitened whitening whitens whiter whites whitest whitewash whitewash's whitewashed whitewashes whitewashing whittle whittled whittles whittling whizz whizzed whizzes whizzing who who'd who'll who're who's who've whoa whodunit whodunit's whodunits whoever whole wholehearted wholeheartedly wholes wholesale wholesale's wholesaled wholesaler wholesaler's wholesalers wholesales wholesaling wholesome wholly whom whoop whooped whooping whoops whoosh whoosh's whooshed whooshes whooshing whopper whopper's whoppers whore whore's whores whose why whys wick wick's wicked wickeder wickedest wickedly wickedness wickedness's wicker wicker's wickers wicket wicket's wickets wicks wide widely widen widened widening widens wider widespread widest widow widow's widowed widower widower's widowers widowing widows width width's widths wield wielded wielding wields wiener wiener's wieners wife wife's wig wig's wigged wigging wiggle wiggled wiggles wiggling wigs wigwam wigwam's wigwams wild wildcat wildcats wildcatted wildcatting wilded wilder wilderness wilderness's wildernesses wildest wildfire wildfire's wildfires wilding wildlife wildlife's wildly wildness wildness's wilds wile wiles wilful wilfully wilier wiliest will willed willing willinger willingest willingly willingness willingness's willow willow's willowier willowiest willows willowy willpower willpower's wills wilt wilted wilting wilts wily wimp wimped wimpier wimpiest wimping wimps wimpy win wince winced winces winch winch's winched winches winching wincing wind wind's windbreaker windbreakers winded windfall windfall's windfalls windier windiest winding winding's windmill windmill's windmilled windmilling windmills window window's windowing windowpane windowpane's windowpanes windows windowsill windowsill's windowsills windpipe windpipe's windpipes winds windscreen windscreen's windscreens windshield windshield's windshields windsurf windsurfed windsurfing windsurfs windswept windy wine wine's wined wineglass wineglass's wineglasses wines wing wing's winged wingers winging wings wingspan wingspan's wingspans wingtip wingtips wining wink winked winking winks winner winner's winners winning winnings wino wino's winos wins winsome winsomer winsomest winter winter's wintered wintering winters wintertime wintertime's wintrier wintriest wintry wipe wiped wiper wiper's wipers wipes wiping wire wire's wired wires wiretap wiretap's wiretapped wiretapping wiretaps wirier wiriest wiring wiring's wiry wisdom wisdom's wise wisecrack wisecrack's wisecracked wisecracking wisecracks wiselier wiseliest wisely wiser wises wisest wish wishbone wishbone's wishbones wished wishes wishful wishing wisp wisp's wispier wispiest wisps wispy wist wistful wistfully wit wit's witch witch's witchcraft witchcraft's witched witches witching wite with withdraw withdrawal withdrawal's withdrawals withdrawing withdrawn withdraws withdrew withe withed wither withered withering withers withes withheld withhold withholding withholds within withing without withs withstand withstanding withstands withstood witless witness witness's witnessed witnesses witnessing wits witticism witticism's witticisms wittier wittiest witting witty wive wives wives's wizard wizard's wizards wizened wobble wobbled wobbles wobblier wobblies wobbliest wobbling wobbly woe woe's woebegone woes wok wok's woke woken woks wolf wolf's wolfed wolfing wolfs wolves wolves's woman woman's womanhood womanhood's womankind womankind's womb womb's wombat wombat's wombats wombs women women's won won't wonder wonder's wondered wonderful wonderfully wondering wonderland wonderland's wonderlands wonders wondrous wont wont's woo wood wood's woodchuck woodchuck's woodchucks wooded wooden woodener woodenest woodier woodies woodiest wooding woodland woodland's woodlands woodpecker woodpecker's woodpeckers woods woodsman woodsman's woodsmen woodwind woodwinds woodwork woodwork's woody wooed woof woof's woofed woofing woofs wooing wool wool's woolie woolier woolies wooliest woollen woollens woollier woollies woolliest woolly wooly woos woozier wooziest woozy word word's worded wordier wordiest wording wording's wordings words wordy wore work work's workable workaholic workaholics workbench workbench's workbenches workbook workbook's workbooks worked worker worker's workers workfare workforce working working's workings workload workload's workloads workman workman's workmanlike workmanship workmanship's workmen workout workout's workouts workplace works worksheet worksheets workshop workshop's workshops workstation workstations world world's worldlier worldliest worldly worlds worldwide worm worm's wormed wormhole wormholes worming worms worn worried worries worrisome worry worrying worryings worse worsen worsened worsening worsens worship worshipped worshipper worshippers worshipping worships worst worsted worsting worsts worth worthier worthies worthiest worthless worthwhile worthy wost wot would would've wouldn't woulds wound wound's wounded wounder wounding wounds wove woven wovens wow wowed wowing wows wrangle wrangled wrangler wrangler's wranglers wrangles wrangling wrap wrapped wrapper wrapper's wrappers wrapping wrapping's wrappings wraps wrapt wrath wrath's wrathed wrathing wraths wreak wreaked wreaking wreaks wreath wreath's wreathe wreathed wreathes wreathing wreaths wreck wreckage wreckage's wrecked wrecker wrecker's wrecking wrecks wren wren's wrench wrench's wrenched wrenches wrenching wrens wrest wrested wresting wrestle wrestled wrestler wrestler's wrestlers wrestles wrestling wrestling's wrests wretch wretch's wretched wretcheder wretchedest wretches wried wrier wries wriest wriggle wriggled wriggles wriggling wright wright's wring wringer wringer's wringers wringing wrings wrinkle wrinkle's wrinkled wrinkles wrinkling wrist wrist's wrists wristwatch wristwatch's wristwatches writ writ's writable write writer writer's writers writes writhe writhed writhes writhing writing writing's writings writs written wrong wrongdoer wrongdoer's wrongdoers wrongdoing wrongdoing's wrongdoings wronged wronger wrongest wrongful wrongfully wronging wrongly wrongs wrote wrought wrung wry wryer wryest wrying wryly x xenophobia xenophobia's xenophobic xylophone xylophone's xylophones y y'all ya yacht yacht's yachted yachting yachts yak yak's yakked yakking yaks yam yam's yams yank yanked yanking yanks yap yapped yapping yaps yard yard's yards yardstick yardstick's yardsticks yarmulke yarmulke's yarmulkes yarn yarn's yarns yawn yawned yawning yawns yeah yeahs year year's yearbook yearbook's yearbooks yearlies yearling yearling's yearly yearn yearned yearning yearning's yearnings yearns years yeast yeast's yeasts yell yelled yelling yellow yellow's yellowed yellower yellowest yellowing yellowish yellows yells yelp yelped yelping yelps yen yen's yens yep yeps yes yeses yessed yessing yest yesterday yesterday's yesterdays yet yeti yeti's yew yew's yews yield yielded yielding yields yippee yippees yo yodel yodelled yodelling yodels yoga yoga's yogurt yogurt's yogurts yoke yoke's yoked yokel yokel's yokels yokes yoking yolk yolk's yolks yonder you you'd you'll you're you've young younger youngest youngster youngster's youngsters your yours yourself yourselves yous youth youth's youthful youths yowl yowled yowling yowls yuck yucked yuckier yuckiest yucking yucks yucky yum yummier yummiest yummy yuppie yuppies yuppy z zanied zanier zanies zaniest zany zanying zap zapped zapping zaps zeal zeal's zealous zealously zebra zebra's zebras zenith zenith's zeniths zero zero's zeroed zeroes zeroing zeros zest zest's zests zeta zeta's zigzag zigzag's zigzagged zigzagging zigzags zillion zillion's zillions zinc zinc's zinced zincing zincked zincking zincs zip zip's zipped zipper zipper's zippered zippering zippers zipping zips zit zits zodiac zodiac's zodiacs zombie zombie's zombies zone zone's zoned zones zoning zoo zoo's zoological zoologist zoologist's zoologists zoology zoology's zoom zoomed zooming zooms zoos zucchini zucchini's zucchinis clair clair's clairs You have received this book through Project Gutenberg Disclaimer: All persons concerned disclaim any and all reponsbility that this etext is perfectly accurate. No pretenses in any manner are made that this text should be thought of as an authoritative edition in any respect. This book was TYPED in by Judy Boss eng003@zeus.unomaha.edu on Internet eng003@unoma1 on Bitnet (Judy now has a scanner) Another edition of Paradise Lost could also be available shortly. (We still have to complete our copyright analysis to insure these releases do not infringe on anyone's copyrights.) Further information about Project Gutenberg is available at: hart@vmd.cso.uiuc.edu on Internet hart@uiucvmd on Bitnet or send a SASLE (Self Address Stamped Legal Envelope) to: Prof. Michael S. Hart c/o Project Gutenberg 405 West Elm Street Urbana, IL 61801-3231 PARADISE LOST BOOK I. Of Mans First Disobedience, and the Fruit Of that Forbidden Tree, whose mortal tast Brought Death into the World, and all our woe, With loss of EDEN, till one greater Man Restore us, and regain the blissful Seat, Sing Heav'nly Muse, that on the secret top Of OREB, or of SINAI, didst inspire That Shepherd, who first taught the chosen Seed, In the Beginning how the Heav'ns and Earth Rose out of CHAOS: Or if SION Hill Delight thee more, and SILOA'S Brook that flow'd Fast by the Oracle of God; I thence Invoke thy aid to my adventrous Song, That with no middle flight intends to soar Above th' AONIAN Mount, while it pursues Things unattempted yet in Prose or Rhime. And chiefly Thou O Spirit, that dost prefer Before all Temples th' upright heart and pure, Instruct me, for Thou know'st; Thou from the first Wast present, and with mighty wings outspread Dove-like satst brooding on the vast Abyss And mad'st it pregnant: What in me is dark Illumine, what is low raise and support; That to the highth of this great Argument I may assert th' Eternal Providence, And justifie the wayes of God to men. Say first, for Heav'n hides nothing from thy view Nor the deep Tract of Hell, say first what cause Mov'd our Grand Parents in that happy State, Favour'd of Heav'n so highly, to fall off From their Creator, and transgress his Will For one restraint, Lords of the World besides? Who first seduc'd them to that fowl revolt? Th' infernal Serpent; he it was, whose guile Stird up with Envy and Revenge, deceiv'd The Mother of Mankinde, what time his Pride Had cast him out from Heav'n, with all his Host Of Rebel Angels, by whose aid aspiring To set himself in Glory above his Peers, He trusted to have equal'd the most High, If he oppos'd; and with ambitious aim Against the Throne and Monarchy of God Rais'd impious War in Heav'n and Battel proud With vain attempt. Him the Almighty Power Hurld headlong flaming from th' Ethereal Skie With hideous ruine and combustion down To bottomless perdition, there to dwell In Adamantine Chains and penal Fire, Who durst defie th' Omnipotent to Arms. Nine times the Space that measures Day and Night To mortal men, he with his horrid crew Lay vanquisht, rowling in the fiery Gulfe Confounded though immortal: But his doom Reserv'd him to more wrath; for now the thought Both of lost happiness and lasting pain Torments him; round he throws his baleful eyes That witness'd huge affliction and dismay Mixt with obdurate pride and stedfast hate: At once as far as Angels kenn he views The dismal Situation waste and wilde, A Dungeon horrible, on all sides round As one great Furnace flam'd, yet from those flames No light, but rather darkness visible Serv'd only to discover sights of woe, Regions of sorrow, doleful shades, where peace And rest can never dwell, hope never comes That comes to all; but torture without end Still urges, and a fiery Deluge, fed With ever-burning Sulphur unconsum'd: Such place Eternal Justice had prepar'd For those rebellious, here their Prison ordain'd In utter darkness, and their portion set As far remov'd from God and light of Heav'n As from the Center thrice to th' utmost Pole. O how unlike the place from whence they fell! There the companions of his fall, o'rewhelm'd With Floods and Whirlwinds of tempestuous fire, He soon discerns, and weltring by his side One next himself in power, and next in crime, Long after known in PALESTINE, and nam'd BEELZEBUB. To whom th' Arch-Enemy, And thence in Heav'n call'd Satan, with bold words Breaking the horrid silence thus began. If thou beest he; But O how fall'n! how chang'd From him, who in the happy Realms of Light Cloth'd with transcendent brightnes didst outshine Myriads though bright: If he whom mutual league, United thoughts and counsels, equal hope, And hazard in the Glorious Enterprize, Joynd with me once, now misery hath joynd In equal ruin: into what Pit thou seest From what highth fal'n, so much the stronger provd He with his Thunder: and till then who knew The force of those dire Arms? yet not for those Nor what the Potent Victor in his rage Can else inflict do I repent or change, Though chang'd in outward lustre; that fixt mind And high disdain, from sence of injur'd merit, That with the mightiest rais'd me to contend, And to the fierce contention brought along Innumerable force of Spirits arm'd That durst dislike his reign, and me preferring, His utmost power with adverse power oppos'd In dubious Battel on the Plains of Heav'n, And shook his throne. What though the field be lost? All is not lost; the unconquerable Will, And study of revenge, immortal hate, And courage never to submit or yield: And what is else not to be overcome? That Glory never shall his wrath or might Extort from me. To bow and sue for grace With suppliant knee, and deifie his power Who from the terrour of this Arm so late Doubted his Empire, that were low indeed, That were an ignominy and shame beneath This downfall; since by Fate the strength of Gods And this Empyreal substance cannot fail, Since through experience of this great event In Arms not worse, in foresight much advanc't, We may with more successful hope resolve To wage by force or guile eternal Warr Irreconcileable, to our grand Foe, Who now triumphs, and in th' excess of joy Sole reigning holds the Tyranny of Heav'n. So spake th' Apostate Angel, though in pain, Vaunting aloud, but rackt with deep despare: And him thus answer'd soon his bold Compeer. O Prince, O Chief of many Throned Powers, That led th' imbattelld Seraphim to Warr Under thy conduct, and in dreadful deeds Fearless, endanger'd Heav'ns perpetual King; And put to proof his high Supremacy, Whether upheld by strength, or Chance, or Fate, Too well I see and rue the dire event, That with sad overthrow and foul defeat Hath lost us Heav'n, and all this mighty Host In horrible destruction laid thus low, As far as Gods and Heav'nly Essences Can Perish: for the mind and spirit remains Invincible, and vigour soon returns, Though all our Glory extinct, and happy state Here swallow'd up in endless misery. But what if he our Conquerour, (whom I now Of force believe Almighty, since no less Then such could hav orepow'rd such force as ours) Have left us this our spirit and strength intire Strongly to suffer and support our pains, That we may so suffice his vengeful ire, Or do him mightier service as his thralls By right of Warr, what e're his business be Here in the heart of Hell to work in Fire, Or do his Errands in the gloomy Deep; What can it then avail though yet we feel Strength undiminisht, or eternal being To undergo eternal punishment? Whereto with speedy words th' Arch-fiend reply'd. Fall'n Cherube, to be weak is miserable Doing or Suffering: but of this be sure, To do ought good never will be our task, But ever to do ill our sole delight, As being the contrary to his high will Whom we resist. If then his Providence Out of our evil seek to bring forth good, Our labour must be to pervert that end, And out of good still to find means of evil; Which oft times may succeed, so as perhaps Shall grieve him, if I fail not, and disturb His inmost counsels from their destind aim. But see the angry Victor hath recall'd His Ministers of vengeance and pursuit Back to the Gates of Heav'n: The Sulphurous Hail Shot after us in storm, oreblown hath laid The fiery Surge, that from the Precipice Of Heav'n receiv'd us falling, and the Thunder, Wing'd with red Lightning and impetuous rage, Perhaps hath spent his shafts, and ceases now To bellow through the vast and boundless Deep. Let us not slip th' occasion, whether scorn, Or satiate fury yield it from our Foe. Seest thou yon dreary Plain, forlorn and wilde, The seat of desolation, voyd of light, Save what the glimmering of these livid flames Casts pale and dreadful? Thither let us tend From off the tossing of these fiery waves, There rest, if any rest can harbour there, And reassembling our afflicted Powers, Consult how we may henceforth most offend Our Enemy, our own loss how repair, How overcome this dire Calamity, What reinforcement we may gain from Hope, If not what resolution from despare. Thus Satan talking to his neerest Mate With Head up-lift above the wave, and Eyes That sparkling blaz'd, his other Parts besides Prone on the Flood, extended long and large Lay floating many a rood, in bulk as huge As whom the Fables name of monstrous size, TITANIAN, or EARTH-BORN, that warr'd on JOVE, BRIARIOS or TYPHON, whom the Den By ancient TARSUS held, or that Sea-beast LEVIATHAN, which God of all his works Created hugest that swim th' Ocean stream: Him haply slumbring on the NORWAY foam The Pilot of some small night-founder'd Skiff, Deeming some Island, oft, as Sea-men tell, With fixed Anchor in his skaly rind Moors by his side under the Lee, while Night Invests the Sea, and wished Morn delayes: So stretcht out huge in length the Arch-fiend lay Chain'd on the burning Lake, nor ever thence Had ris'n or heav'd his head, but that the will And high permission of all-ruling Heaven Left him at large to his own dark designs, That with reiterated crimes he might Heap on himself damnation, while he sought Evil to others, and enrag'd might see How all his malice serv'd but to bring forth Infinite goodness, grace and mercy shewn On Man by him seduc't, but on himself Treble confusion, wrath and vengeance pour'd. Forthwith upright he rears from off the Pool His mighty Stature; on each hand the flames Drivn backward slope their pointing spires, & rowld In billows, leave i'th' midst a horrid Vale. Then with expanded wings he stears his flight Aloft, incumbent on the dusky Air That felt unusual weight, till on dry Land He lights, if it were Land that ever burn'd With solid, as the Lake with liquid fire; And such appear'd in hue, as when the force Of subterranean wind transports a Hill Torn from PELORUS, or the shatter'd side Of thundring AETNA, whose combustible And fewel'd entrals thence conceiving Fire, Sublim'd with Mineral fury, aid the Winds, And leave a singed bottom all involv'd With stench and smoak: Such resting found the sole Of unblest feet. Him followed his next Mate, Both glorying to have scap't the STYGIAN flood As Gods, and by their own recover'd strength, Not by the sufferance of supernal Power. Is this the Region, this the Soil, the Clime, Said then the lost Arch Angel, this the seat That we must change for Heav'n, this mournful gloom For that celestial light? Be it so, since hee Who now is Sovran can dispose and bid What shall be right: fardest from him is best Whom reason hath equald, force hath made supream Above his equals. Farewel happy Fields Where Joy for ever dwells: Hail horrours, hail Infernal world, and thou profoundest Hell Receive thy new Possessor: One who brings A mind not to be chang'd by Place or Time. The mind is its own place, and in it self Can make a Heav'n of Hell, a Hell of Heav'n. What matter where, if I be still the same, And what I should be, all but less then hee Whom Thunder hath made greater? Here at least We shall be free; th' Almighty hath not built Here for his envy, will not drive us hence: Here we may reign secure, and in my choyce To reign is worth ambition though in Hell: Better to reign in Hell, then serve in Heav'n. But wherefore let we then our faithful friends, Th' associates and copartners of our loss Lye thus astonisht on th' oblivious Pool, And call them not to share with us their part In this unhappy Mansion, or once more With rallied Arms to try what may be yet Regaind in Heav'n, or what more lost in Hell? So SATAN spake, and him BEELZEBUB Thus answer'd. Leader of those Armies bright, Which but th' Omnipotent none could have foyld, If once they hear that voyce, their liveliest pledge Of hope in fears and dangers, heard so oft In worst extreams, and on the perilous edge Of battel when it rag'd, in all assaults Their surest signal, they will soon resume New courage and revive, though now they lye Groveling and prostrate on yon Lake of Fire, As we erewhile, astounded and amaz'd, No wonder, fall'n such a pernicious highth. He scarce had ceas't when the superiour Fiend Was moving toward the shore; his ponderous shield Ethereal temper, massy, large and round, Behind him cast; the broad circumference Hung on his shoulders like the Moon, whose Orb Through Optic Glass the TUSCAN Artist views At Ev'ning from the top of FESOLE, Or in VALDARNO, to descry new Lands, Rivers or Mountains in her spotty Globe. His Spear, to equal which the tallest Pine Hewn on NORWEGIAN hills, to be the Mast Of some great Ammiral, were but a wand, He walkt with to support uneasie steps Over the burning Marle, not like those steps On Heavens Azure, and the torrid Clime Smote on him sore besides, vaulted with Fire; Nathless he so endur'd, till on the Beach Of that inflamed Sea, he stood and call'd His Legions, Angel Forms, who lay intrans't Thick as Autumnal Leaves that strow the Brooks In VALLOMBROSA, where th' ETRURIAN shades High overarch't imbowr; or scatterd sedge Afloat, when with fierce Winds ORION arm'd Hath vext the Red-Sea Coast, whose waves orethrew BUSIRIS and his MEMPHIAN Chivalrie, VVhile with perfidious hatred they pursu'd The Sojourners of GOSHEN, who beheld From the safe shore their floating Carkases And broken Chariot Wheels, so thick bestrown Abject and lost lay these, covering the Flood, Under amazement of their hideous change. He call'd so loud, that all the hollow Deep Of Hell resounded. Princes, Potentates, Warriers, the Flowr of Heav'n, once yours, now lost, If such astonishment as this can sieze Eternal spirits; or have ye chos'n this place After the toyl of Battel to repose Your wearied vertue, for the ease you find To slumber here, as in the Vales of Heav'n? Or in this abject posture have ye sworn To adore the Conquerour? who now beholds Cherube and Seraph rowling in the Flood With scatter'd Arms and Ensigns, till anon His swift pursuers from Heav'n Gates discern Th' advantage, and descending tread us down Thus drooping, or with linked Thunderbolts Transfix us to the bottom of this Gulfe. Awake, arise, or be for ever fall'n. They heard, and were abasht, and up they sprung Upon the wing, as when men wont to watch On duty, sleeping found by whom they dread, Rouse and bestir themselves ere well awake. Nor did they not perceave the evil plight In which they were, or the fierce pains not feel; Yet to their Generals Voyce they soon obeyd Innumerable. As when the potent Rod Of AMRAMS Son in EGYPTS evill day Wav'd round the Coast, up call'd a pitchy cloud Of LOCUSTS, warping on the Eastern Wind, That ore the Realm of impious PHAROAH hung Like Night, and darken'd all the Land of NILE: So numberless were those bad Angels seen Hovering on wing under the Cope of Hell 'Twixt upper, nether, and surrounding Fires; Till, as a signal giv'n, th' uplifted Spear Of their great Sultan waving to direct Thir course, in even ballance down they light On the firm brimstone, and fill all the Plain; A multitude, like which the populous North Pour'd never from her frozen loyns, to pass RHENE or the DANAW, when her barbarous Sons Came like a Deluge on the South, and spread Beneath GIBRALTAR to the LYBIAN sands. Forthwith from every Squadron and each Band The Heads and Leaders thither hast where stood Their great Commander; Godlike shapes and forms Excelling human, Princely Dignities, And Powers that earst in Heaven sat on Thrones; Though of their Names in heav'nly Records now Be no memorial, blotted out and ras'd By thir Rebellion, from the Books of Life. Nor had they yet among the Sons of EVE Got them new Names, till wandring ore the Earth, Through Gods high sufferance for the tryal of man, By falsities and lyes the greatest part Of Mankind they corrupted to forsake God their Creator, and th' invisible Glory of him, that made them, to transform Oft to the Image of a Brute, adorn'd With gay Religions full of Pomp and Gold, And Devils to adore for Deities: Then were they known to men by various Names, And various Idols through the Heathen World. Say, Muse, their Names then known, who first, who last, Rous'd from the slumber, on that fiery Couch, At thir great Emperors call, as next in worth Came singly where he stood on the bare strand, While the promiscuous croud stood yet aloof? The chief were those who from the Pit of Hell Roaming to seek their prey on earth, durst fix Their Seats long after next the Seat of God, Their Altars by his Altar, Gods ador'd Among the Nations round, and durst abide JEHOVAH thundring out of SION, thron'd Between the Cherubim; yea, often plac'd Within his Sanctuary it self their Shrines, Abominations; and with cursed things His holy Rites, and solemn Feasts profan'd, And with their darkness durst affront his light. First MOLOCH, horrid King besmear'd with blood Of human sacrifice, and parents tears, Though for the noyse of Drums and Timbrels loud Their childrens cries unheard, that past through fire To his grim Idol. Him the AMMONITE Worshipt in RABBA and her watry Plain, In ARGOB and in BASAN, to the stream Of utmost ARNON. Nor content with such Audacious neighbourhood, the wisest heart Of SOLOMON he led by fraud to build His Temple right against the Temple of God On that opprobrious Hill, and made his Grove The pleasant Vally of HINNOM, TOPHET thence And black GEHENNA call'd, the Type of Hell. Next CHEMOS, th' obscene dread of MOABS Sons, From AROER to NEBO, and the wild Of Southmost ABARIM; in HESEBON And HERONAIM, SEONS Realm, beyond The flowry Dale of SIBMA clad with Vines, And ELEALE to th' ASPHALTICK Pool. PEOR his other Name, when he entic'd ISRAEL in SITTIM on their march from NILE To do him wanton rites, which cost them woe. Yet thence his lustful Orgies he enlarg'd Even to that Hill of scandal, by the Grove Of MOLOCH homicide, lust hard by hate; Till good JOSIAH drove them thence to Hell. With these came they, who from the bordring flood Of old EUPHRATES to the Brook that parts EGYPT from SYRIAN ground, had general Names Of BAALIM and ASHTAROTH, those male, These Feminine. For Spirits when they please Can either Sex assume, or both; so soft And uncompounded is their Essence pure, Not ti'd or manacl'd with joynt or limb, Nor founded on the brittle strength of bones, Like cumbrous flesh; but in what shape they choose Dilated or condens't, bright or obscure, Can execute their aerie purposes, And works of love or enmity fulfill. For those the Race of ISRAEL oft forsook Their living strength, and unfrequented left His righteous Altar, bowing lowly down To bestial Gods; for which their heads as low Bow'd down in Battel, sunk before the Spear Of despicable foes. With these in troop Came ASTORETH, whom the PHOENICIANS call'd ASTARTE, Queen of Heav'n, with crescent Horns; To whose bright Image nightly by the Moon SIDONIAN Virgins paid their Vows and Songs, In SION also not unsung, where stood Her Temple on th' offensive Mountain, built By that uxorious King, whose heart though large, Beguil'd by fair Idolatresses, fell To Idols foul. THAMMUZ came next behind, Whose annual wound in LEBANON allur'd The SYRIAN Damsels to lament his fate In amorous dittyes all a Summers day, While smooth ADONIS from his native Rock Ran purple to the Sea, suppos'd with blood Of THAMMUZ yearly wounded: the Love-tale Infected SIONS daughters with like heat, Whose wanton passions in the sacred Porch EZEKIEL saw, when by the Vision led His eye survay'd the dark Idolatries Of alienated JUDAH. Next came one Who mourn'd in earnest, when the Captive Ark Maim'd his brute Image, head and hands lopt off In his own Temple, on the grunsel edge, Where he fell flat, and sham'd his Worshipers: DAGON his Name, Sea Monster, upward Man And downward Fish: yet had his Temple high Rear'd in AZOTUS, dreaded through the Coast Of PALESTINE, in GATH and ASCALON, And ACCARON and GAZA's frontier bounds. Him follow'd RIMMON, whose delightful Seat Was fair DAMASCUS, on the fertil Banks Of ABBANA and PHARPHAR, lucid streams. He also against the house of God was bold: A Leper once he lost and gain'd a King, AHAZ his sottish Conquerour, whom he drew Gods Altar to disparage and displace For one of SYRIAN mode, whereon to burn His odious offrings, and adore the Gods Whom he had vanquisht. After these appear'd A crew who under Names of old Renown, OSIRIS, ISIS, ORUS and their Train With monstrous shapes and sorceries abus'd Fanatic EGYPT and her Priests, to seek Thir wandring Gods disguis'd in brutish forms Rather then human. Nor did ISRAEL scape Th' infection when their borrow'd Gold compos'd The Calf in OREB: and the Rebel King Doubl'd that sin in BETHEL and in DAN, Lik'ning his Maker to the Grazed Ox, JEHOVAH, who in one Night when he pass'd From EGYPT marching, equal'd with one stroke Both her first born and all her bleating Gods. BELIAL came last, then whom a Spirit more lewd Fell not from Heaven, or more gross to love Vice for it self: To him no Temple stood Or Altar smoak'd; yet who more oft then hee In Temples and at Altars, when the Priest Turns Atheist, as did ELY'S Sons, who fill'd With lust and violence the house of God. In Courts and Palaces he also Reigns And in luxurious Cities, where the noyse Of riot ascends above thir loftiest Towrs, And injury and outrage: And when Night Darkens the Streets, then wander forth the Sons Of BELIAL, flown with insolence and wine. Witness the Streets of SODOM, and that night In GIBEAH, when hospitable Dores Yielded thir Matrons to prevent worse rape. These were the prime in order and in might; The rest were long to tell, though far renown'd, Th' IONIAN Gods, of JAVANS Issue held Gods, yet confest later then Heav'n and Earth Thir boasted Parents; TITAN Heav'ns first born With his enormous brood, and birthright seis'd By younger SATURN, he from mightier JOVE His own and RHEA'S Son like measure found; So JOVE usurping reign'd: these first in CREET And IDA known, thence on the Snowy top Of cold OLYMPUS rul'd the middle Air Thir highest Heav'n; or on the DELPHIAN Cliff, Or in DODONA, and through all the bounds Of DORIC Land; or who with SATURN old Fled over ADRIA to th' HESPERIAN Fields, And ore the CELTIC roam'd the utmost Isles. All these and more came flocking; but with looks Down cast and damp, yet such wherein appear'd Obscure som glimps of joy, to have found thir chief Not in despair, to have found themselves not lost In loss it self; which on his count'nance cast Like doubtful hue: but he his wonted pride Soon recollecting, with high words, that bore Semblance of worth not substance, gently rais'd Their fainted courage, and dispel'd their fears. Then strait commands that at the warlike sound Of Trumpets loud and Clarions be upreard His mighty Standard; that proud honour claim'd AZAZEL as his right, a Cherube tall: Who forthwith from the glittering Staff unfurld Th' Imperial Ensign, which full high advanc't Shon like a Meteor streaming to the Wind With Gemms and Golden lustre rich imblaz'd, Seraphic arms and Trophies: all the while Sonorous mettal blowing Martial sounds: At which the universal Host upsent A shout that tore Hells Concave, and beyond Frighted the Reign of CHAOS and old Night. All in a moment through the gloom were seen Ten thousand Banners rise into the Air With Orient Colours waving: with them rose A Forrest huge of Spears: and thronging Helms Appear'd, and serried Shields in thick array Of depth immeasurable: Anon they move In perfect PHALANX to the Dorian mood Of Flutes and soft Recorders; such as rais'd To highth of noblest temper Hero's old Arming to Battel, and in stead of rage Deliberate valour breath'd, firm and unmov'd With dread of death to flight or foul retreat, Nor wanting power to mitigate and swage With solemn touches, troubl'd thoughts, and chase Anguish and doubt and fear and sorrow and pain From mortal or immortal minds. Thus they Breathing united force with fixed thought Mov'd on in silence to soft Pipes that charm'd Thir painful steps o're the burnt soyle; and now Advanc't in view they stand, a horrid Front Of dreadful length and dazling Arms, in guise Of Warriers old with order'd Spear and Shield, Awaiting what command thir mighty Chief Had to impose: He through the armed Files Darts his experienc't eye, and soon traverse The whole Battalion views, thir order due, Thir visages and stature as of Gods, Thir number last he summs. And now his heart Distends with pride, and hardning in his strength Glories: For never since created man, Met such imbodied force, as nam'd with these Could merit more then that small infantry Warr'd on by Cranes: though all the Giant brood Of PHLEGRA with th' Heroic Race were joyn'd That fought at THEB'S and ILIUM, on each side Mixt with auxiliar Gods; and what resounds In Fable or ROMANCE of UTHERS Son Begirt with BRITISH and ARMORIC Knights; And all who since, Baptiz'd or Infidel Jousted in ASPRAMONT or MONTALBAN, DAMASCO, or MAROCCO, or TREBISOND, Or whom BISERTA sent from AFRIC shore When CHARLEMAIN with all his Peerage fell By FONTARABBIA. Thus far these beyond Compare of mortal prowess, yet observ'd Thir dread Commander: he above the rest In shape and gesture proudly eminent Stood like a Towr; his form had yet not lost All her Original brightness, nor appear'd Less then Arch Angel ruind, and th' excess Of Glory obscur'd: As when the Sun new ris'n Looks through the Horizontal misty Air Shorn of his Beams, or from behind the Moon In dim Eclips disastrous twilight sheds On half the Nations, and with fear of change Perplexes Monarchs. Dark'n'd so, yet shon Above them all th' Arch Angel: but his face Deep scars of Thunder had intrencht, and care Sat on his faded cheek, but under Browes Of dauntless courage, and considerate Pride Waiting revenge: cruel his eye, but cast Signs of remorse and passion to behold The fellows of his crime, the followers rather (Far other once beheld in bliss) condemn'd For ever now to have their lot in pain, Millions of Spirits for his fault amerc't Of Heav'n, and from Eternal Splendors flung For his revolt, yet faithfull how they stood, Thir Glory witherd. As when Heavens Fire Hath scath'd the Forrest Oaks, or Mountain Pines, With singed top their stately growth though bare Stands on the blasted Heath. He now prepar'd To speak; whereat their doubl'd Ranks they bend From Wing to Wing, and half enclose him round With all his Peers: attention held them mute. Thrice he assayd, and thrice in spite of scorn, Tears such as Angels weep, burst forth: at last Words interwove with sighs found out their way. O Myriads of immortal Spirits, O Powers Matchless, but with th' Almighty, and that strife Was not inglorious, though th' event was dire, As this place testifies, and this dire change Hateful to utter: but what power of mind Foreseeing or presaging, from the Depth Of knowledge past or present, could have fear'd, How such united force of Gods, how such As stood like these, could ever know repulse? For who can yet beleeve, though after loss, That all these puissant Legions, whose exile Hath emptied Heav'n, shall faile to re-ascend Self-rais'd, and repossess their native seat. For me, be witness all the Host of Heav'n, If counsels different, or danger shun'd By me, have lost our hopes. But he who reigns Monarch in Heav'n, till then as one secure Sat on his Throne, upheld by old repute, Consent or custome, and his Regal State Put forth at full, but still his strength conceal'd, Which tempted our attempt, and wrought our fall. Henceforth his might we know, and know our own So as not either to provoke, or dread New warr, provok't; our better part remains To work in close design, by fraud or guile What force effected not: that he no less At length from us may find, who overcomes By force, hath overcome but half his foe. Space may produce new Worlds; whereof so rife There went a fame in Heav'n that he ere long Intended to create, and therein plant A generation, whom his choice regard Should favour equal to the Sons of Heaven: Thither, if but to prie, shall be perhaps Our first eruption, thither or elsewhere: For this Infernal Pit shall never hold Caelestial Spirits in Bondage, nor th' Abysse Long under darkness cover. But these thoughts Full Counsel must mature: Peace is despaird, For who can think Submission? Warr then, Warr Open or understood must be resolv'd. He spake: and to confirm his words, out-flew Millions of flaming swords, drawn from the thighs Of mighty Cherubim; the sudden blaze Far round illumin'd hell: highly they rag'd Against the Highest, and fierce with grasped arm's Clash'd on their sounding shields the din of war, Hurling defiance toward the vault of Heav'n. There stood a Hill not far whose griesly top Belch'd fire and rowling smoak; the rest entire Shon with a glossie scurff, undoubted sign That in his womb was hid metallic Ore, The work of Sulphur. Thither wing'd with speed A numerous Brigad hasten'd. As when bands Of Pioners with Spade and Pickaxe arm'd Forerun the Royal Camp, to trench a Field, Or cast a Rampart. MAMMON led them on, MAMMON, the least erected Spirit that fell From heav'n, for ev'n in heav'n his looks & thoughts Were always downward bent, admiring more The riches of Heav'ns pavement, trod'n Gold, Then aught divine or holy else enjoy'd In vision beatific: by him first Men also, and by his suggestion taught, Ransack'd the Center, and with impious hands Rifl'd the bowels of thir mother Earth For Treasures better hid. Soon had his crew Op'nd into the Hill a spacious wound And dig'd out ribs of Gold. Let none admire That riches grow in Hell; that soyle may best Deserve the pretious bane. And here let those Who boast in mortal things, and wondring tell Of BABEL, and the works of MEMPHIAN Kings, Learn how thir greatest Monuments of Fame, And Strength and Art are easily outdone By Spirits reprobate, and in an hour What in an age they with incessant toyle And hands innumerable scarce perform Nigh on the Plain in many cells prepar'd, That underneath had veins of liquid fire Sluc'd from the Lake, a second multitude With wondrous Art founded the massie Ore, Severing each kinde, and scum'd the Bullion dross: A third as soon had form'd within the ground A various mould, and from the boyling cells By strange conveyance fill'd each hollow nook, As in an Organ from one blast of wind To many a row of Pipes the sound-board breaths. Anon out of the earth a Fabrick huge Rose like an Exhalation, with the sound Of Dulcet Symphonies and voices sweet, Built like a Temple, where PILASTERS round Were set, and Doric pillars overlaid With Golden Architrave; nor did there want Cornice or Freeze, with bossy Sculptures grav'n, The Roof was fretted Gold. Not BABILON, Nor great ALCAIRO such magnificence Equal'd in all thir glories, to inshrine BELUS or SERAPIS thir Gods, or seat Thir Kings, when AEGYPT with ASSYRIA strove In wealth and luxurie. Th' ascending pile Stood fixt her stately highth, and strait the dores Op'ning thir brazen foulds discover wide Within, her ample spaces, o're the smooth And level pavement: from the arched roof Pendant by suttle Magic many a row Of Starry Lamps and blazing Cressets fed With Naphtha and ASPHALTUS yeilded light As from a sky. The hasty multitude Admiring enter'd, and the work some praise And some the Architect: his hand was known In Heav'n by many a Towred structure high, Where Scepter'd Angels held thir residence, And sat as Princes, whom the supreme King Exalted to such power, and gave to rule, Each in his Herarchie, the Orders bright. Nor was his name unheard or unador'd In ancient Greece; and in AUSONIAN land Men call'd him MULCIBER; and how he fell From Heav'n, they fabl'd, thrown by angry JOVE Sheer o're the Chrystal Battlements: from Morn To Noon he fell, from Noon to dewy Eve, A Summers day; and with the setting Sun Dropt from the Zenith like a falling Star, On LEMNOS th' AEGAEAN Ile: thus they relate, Erring; for he with this rebellious rout Fell long before; nor aught avail'd him now To have built in Heav'n high Towrs; nor did he scape By all his Engins, but was headlong sent With his industrious crew to build in hell. Mean while the winged Haralds by command Of Sovran power, with awful Ceremony And Trumpets sound throughout the Host proclaim A solemn Councel forthwith to be held At PANDAEMONIUM, the high Capital Of Satan and his Peers: thir summons call'd From every and Band squared Regiment By place or choice the worthiest; they anon With hundreds and with thousands trooping came Attended: all access was throng'd, the Gates And Porches wide, but chief the spacious Hall (Though like a cover'd field, where Champions bold Wont ride in arm'd, and at the Soldans chair Defi'd the best of Panim chivalry To mortal combat or carreer with Lance) Thick swarm'd, both on the ground and in the air, Brusht with the hiss of russling wings. As Bees In spring time, when the Sun with Taurus rides, Poure forth thir populous youth about the Hive In clusters; they among fresh dews and flowers Flie to and fro, or on the smoothed Plank, The suburb of thir Straw-built Cittadel, New rub'd with Baume, expatiate and confer Thir State affairs. So thick the aerie crowd Swarm'd and were straitn'd; till the Signal giv'n, Behold a wonder! they but now who seemd In bigness to surpass Earths Giant Sons Now less then smallest Dwarfs, in narrow room Throng numberless, like that Pigmean Race Beyond the INDIAN Mount, or Faerie Elves, Whose midnight Revels, by a Forrest side Or Fountain fome belated Peasant sees, Or dreams he sees, while over head the Moon Sits Arbitress, and neerer to the Earth Wheels her pale course, they on thir mirth & dance Intent, with jocond Music charm his ear; At once with joy and fear his heart rebounds. Thus incorporeal Spirits to smallest forms Reduc'd thir shapes immense, and were at large, Though without number still amidst the Hall Of that infernal Court. But far within And in thir own dimensions like themselves The great Seraphic Lords and Cherubim In close recess and secret conclave sat A thousand Demy-Gods on golden seat's, Frequent and full. After short silence then And summons read, the great consult began. THE END OF THE FIRST BOOK. PARADISE LOST BOOK II. High on a Throne of Royal State, which far Outshon the wealth of ORMUS and of IND, Or where the gorgeous East with richest hand Showrs on her Kings BARBARIC Pearl & Gold, Satan exalted sat, by merit rais'd To that bad eminence; and from despair Thus high uplifted beyond hope, aspires Beyond thus high, insatiate to pursue Vain Warr with Heav'n, and by success untaught His proud imaginations thus displaid. Powers and Dominions, Deities of Heav'n, For since no deep within her gulf can hold Immortal vigor, though opprest and fall'n, I give not Heav'n for lost. From this descent Celestial vertues rising, will appear More glorious and more dread then from no fall, And trust themselves to fear no second fate: Mee though just right, and the fixt Laws of Heav'n Did first create your Leader, next, free choice, With what besides, in Counsel or in Fight, Hath bin achievd of merit, yet this loss Thus farr at least recover'd, hath much more Establisht in a safe unenvied Throne Yeilded with full consent. The happier state In Heav'n, which follows dignity, might draw Envy from each inferior; but who here Will envy whom the highest place exposes Formost to stand against the Thunderers aime Your bulwark, and condemns to greatest share Of endless pain? where there is then no good For which to strive, no strife can grow up there From Faction; for none sure will claim in hell Precedence, none, whose portion is so small Of present pain, that with ambitious mind Will covet more. With this advantage then To union, and firm Faith, and firm accord, More then can be in Heav'n, we now return To claim our just inheritance of old, Surer to prosper then prosperity Could have assur'd us; and by what best way, Whether of open Warr or covert guile, We now debate; who can advise, may speak. He ceas'd, and next him MOLOC, Scepter'd King Stood up, the strongest and the fiercest Spirit That fought in Heav'n; now fiercer by despair: His trust was with th' Eternal to be deem'd Equal in strength, and rather then be less Car'd not to be at all; with that care lost Went all his fear: of God, or Hell, or worse He reckd not, and these words thereafter spake. My sentence is for open Warr: Of Wiles, More unexpert, I boast not: them let those Contrive who need, or when they need, not now. For while they sit contriving, shall the rest, Millions that stand in Arms, and longing wait The Signal to ascend, sit lingring here Heav'ns fugitives, and for thir dwelling place Accept this dark opprobrious Den of shame, The Prison of his Tyranny who Reigns By our delay? no, let us rather choose Arm'd with Hell flames and fury all at once O're Heav'ns high Towrs to force resistless way, Turning our Tortures into horrid Arms Against the Torturer; when to meet the noise Of his Almighty Engin he shall hear Infernal Thunder, and for Lightning see Black fire and horror shot with equal rage Among his Angels; and his Throne it self Mixt with TARTAREAN Sulphur, and strange fire, His own invented Torments. But perhaps The way seems difficult and steep to scale With upright wing against a higher foe. Let such bethink them, if the sleepy drench Of that forgetful Lake benumme not still, That in our proper motion we ascend Up to our native seat: descent and fall To us is adverse. Who but felt of late When the fierce Foe hung on our brok'n Rear Insulting, and pursu'd us through the Deep, With what compulsion and laborious flight We sunk thus low? Th' ascent is easie then; Th' event is fear'd; should we again provoke Our stronger, some worse way his wrath may find To our destruction: if there be in Hell Fear to be worse destroy'd: what can be worse Then to dwell here, driv'n out from bliss, condemn'd In this abhorred deep to utter woe; Where pain of unextinguishable fire Must exercise us without hope of end The Vassals of his anger, when the Scourge Inexorably, and the torturing houre Calls us to Penance? More destroy'd then thus We should be quite abolisht and expire. What fear we then? what doubt we to incense His utmost ire? which to the highth enrag'd, Will either quite consume us, and reduce To nothing this essential, happier farr Then miserable to have eternal being: Or if our substance be indeed Divine, And cannot cease to be, we are at worst On this side nothing; and by proof we feel Our power sufficient to disturb his Heav'n, And with perpetual inrodes to Allarme, Though inaccessible, his fatal Throne: Which if not Victory is yet Revenge. He ended frowning, and his look denounc'd Desperate revenge, and Battel dangerous To less then Gods. On th' other side up rose BELIAL, in act more graceful and humane; A fairer person lost not Heav'n; he seemd For dignity compos'd and high exploit: But all was false and hollow; though his Tongue Dropt Manna, and could make the worse appear The better reason, to perplex and dash Maturest Counsels: for his thoughts were low; To vice industrious, but to Nobler deeds Timorous and slothful: yet he pleas'd the eare, And with perswasive accent thus began. I should be much for open Warr, O Peers, As not behind in hate; if what was urg'd Main reason to perswade immediate Warr, Did not disswade me most, and seem to cast Ominous conjecture on the whole success: When he who most excels in fact of Arms, In what he counsels and in what excels Mistrustful, grounds his courage on despair And utter dissolution, as the scope Of all his aim, after some dire revenge. First, what Revenge? the Towrs of Heav'n are fill'd With Armed watch, that render all access Impregnable; oft on the bordering Deep Encamp thir Legions, or with obscure wing Scout farr and wide into the Realm of night, Scorning surprize. Or could we break our way By force, and at our heels all Hell should rise With blackest Insurrection, to confound Heav'ns purest Light, yet our great Enemie All incorruptible would on his Throne Sit unpolluted, and th' Ethereal mould Incapable of stain would soon expel Her mischief, and purge off the baser fire Victorious. Thus repuls'd, our final hope Is flat despair: we must exasperate Th' Almighty Victor to spend all his rage, And that must end us, that must be our cure, To be no more; sad cure; for who would loose, Though full of pain, this intellectual being, Those thoughts that wander through Eternity, To perish rather, swallowd up and lost In the wide womb of uncreated night, Devoid of sense and motion? and who knows, Let this be good, whether our angry Foe Can give it, or will ever? how he can Is doubtful; that he never will is sure. Will he, so wise, let loose at once his ire, Belike through impotence, or unaware, To give his Enemies thir wish, and end Them in his anger, whom his anger saves To punish endless? wherefore cease we then? Say they who counsel Warr, we are decreed, Reserv'd and destin'd to Eternal woe; Whatever doing, what can we suffer more, What can we suffer worse? is this then worst, Thus sitting, thus consulting, thus in Arms? What when we fled amain, pursu'd and strook With Heav'ns afflicting Thunder, and besought The Deep to shelter us? this Hell then seem'd A refuge from those wounds: or when we lay Chain'd on the burning Lake? that sure was worse. What if the breath that kindl'd those grim fires Awak'd should blow them into sevenfold rage And plunge us in the Flames? or from above Should intermitted vengeance Arme again His red right hand to plague us? what if all Her stores were op'n'd, and this Firmament Of Hell should spout her Cataracts of Fire, Impendent horrors, threatning hideous fall One day upon our heads; while we perhaps Designing or exhorting glorious Warr, Caught in a fierie Tempest shall be hurl'd Each on his rock transfixt, the sport and prey Of racking whirlwinds, or for ever sunk Under yon boyling Ocean, wrapt in Chains; There to converse with everlasting groans, Unrespited, unpitied, unrepreevd, Ages of hopeless end; this would be worse. Warr therefore, open or conceal'd, alike My voice disswades; for what can force or guile With him, or who deceive his mind, whose eye Views all things at one view? he from heav'ns highth All these our motions vain, sees and derides; Not more Almighty to resist our might Then wise to frustrate all our plots and wiles. Shall we then live thus vile, the race of Heav'n Thus trampl'd, thus expell'd to suffer here Chains & these Torments? better these then worse By my advice; since fate inevitable Subdues us, and Omnipotent Decree, The Victors will. To suffer, as to doe, Our strength is equal, nor the Law unjust That so ordains: this was at first resolv'd, If we were wise, against so great a foe Contending, and so doubtful what might fall. I laugh, when those who at the Spear are bold And vent'rous, if that fail them, shrink and fear What yet they know must follow, to endure Exile, or ignominy, or bonds, or pain, The sentence of thir Conquerour: This is now Our doom; which if we can sustain and bear, Our Supream Foe in time may much remit His anger, and perhaps thus farr remov'd Not mind us not offending, satisfi'd With what is punish't; whence these raging fires Will slack'n, if his breath stir not thir flames. Our purer essence then will overcome Thir noxious vapour, or enur'd not feel, Or chang'd at length, and to the place conformd In temper and in nature, will receive Familiar the fierce heat, and void of pain; This horror will grow milde, this darkness light, Besides what hope the never-ending flight Of future days may bring, what chance, what change Worth waiting, since our present lot appeers For happy though but ill, for ill not worst, If we procure not to our selves more woe. Thus BELIAL with words cloath'd in reasons garb Counsel'd ignoble ease, and peaceful sloath, Not peace: and after him thus MAMMON spake. Either to disinthrone the King of Heav'n We warr, if warr be best, or to regain Our own right lost: him to unthrone we then May hope, when everlasting Fate shall yeild To fickle Chance, and CHAOS judge the strife: The former vain to hope argues as vain The latter: for what place can be for us Within Heav'ns bound, unless Heav'ns Lord supream We overpower? Suppose he should relent And publish Grace to all, on promise made Of new Subjection; with what eyes could we Stand in his presence humble, and receive Strict Laws impos'd, to celebrate his Throne With warbl'd Hymns, and to his Godhead sing Forc't Halleluiah's; while he Lordly sits Our envied Sovran, and his Altar breathes Ambrosial Odours and Ambrosial Flowers, Our servile offerings. This must be our task In Heav'n, this our delight; how wearisom Eternity so spent in worship paid To whom we hate. Let us not then pursue By force impossible, by leave obtain'd Unacceptable, though in Heav'n, our state Of splendid vassalage, but rather seek Our own good from our selves, and from our own Live to our selves, though in this vast recess, Free, and to none accountable, preferring Hard liberty before the easie yoke Of servile Pomp. Our greatness will appear Then most conspicuous, when great things of small, Useful of hurtful, prosperous of adverse We can create, and in what place so e're Thrive under evil, and work ease out of pain Through labour and endurance. This deep world Of darkness do we dread? How oft amidst Thick clouds and dark doth Heav'ns all-ruling Sire Choose to reside, his Glory unobscur'd, And with the Majesty of darkness round Covers his Throne; from whence deep thunders roar Must'ring thir rage, and Heav'n resembles Hell? As he our Darkness, cannot we his Light Imitate when we please? This Desart soile Wants not her hidden lustre, Gemms and Gold; Nor want we skill or art, from whence to raise Magnificence; and what can Heav'n shew more? Our torments also may in length of time Become our Elements, these piercing Fires As soft as now severe, our temper chang'd Into their temper; which must needs remove The sensible of pain. All things invite To peaceful Counsels, and the settl'd State Of order, how in safety best we may Compose our present evils, with regard Of what we are and where, dismissing quite All thoughts of Warr: ye have what I advise. He scarce had finisht, when such murmur filld Th' Assembly, as when hollow Rocks retain The sound of blustring winds, which all night long Had rous'd the Sea, now with hoarse cadence lull Sea-faring men orewatcht, whose Bark by chance Or Pinnace anchors in a craggy Bay After the Tempest: Such applause was heard As MAMMON ended, and his Sentence pleas'd, Advising peace: for such another Field They dreaded worse then Hell: so much the fear Of Thunder and the Sword of MICHAEL Wrought still within them; and no less desire To found this nether Empire, which might rise By pollicy, and long process of time, In emulation opposite to Heav'n. Which when BEELZEBUB perceiv'd, then whom, SATAN except, none higher sat, with grave Aspect he rose, and in his rising seem'd A Pillar of State; deep on his Front engraven Deliberation sat and publick care; And Princely counsel in his face yet shon, Majestick though in ruin: sage he stood With ATLANTEAN shoulders fit to bear The weight of mightiest Monarchies; his look Drew audience and attention still as Night Or Summers Noon-tide air, while thus he spake. Thrones and imperial Powers, off-spring of heav'n, Ethereal Vertues; or these Titles now Must we renounce, and changing stile be call'd Princes of Hell? for so the popular vote Inclines, here to continue, and build up here A growing Empire; doubtless; while we dream, And know not that the King of Heav'n hath doom'd This place our dungeon, not our safe retreat Beyond his Potent arm, to live exempt From Heav'ns high jurisdiction, in new League Banded against his Throne, but to remaine In strictest bondage, though thus far remov'd, Under th' inevitable curb, reserv'd His captive multitude: For he, be sure, In highth or depth, still first and last will Reign Sole King, and of his Kingdom loose no part By our revolt, but over Hell extend His Empire, and with Iron Scepter rule Us here, as with his Golden those in Heav'n. What sit we then projecting Peace and Warr? Warr hath determin'd us, and foild with loss Irreparable; tearms of peace yet none Voutsaf't or sought; for what peace will be giv'n To us enslav'd, but custody severe, And stripes, and arbitrary punishment Inflicted? and what peace can we return, But to our power hostility and hate, Untam'd reluctance, and revenge though slow, Yet ever plotting how the Conquerour least May reap his conquest, and may least rejoyce In doing what we most in suffering feel? Nor will occasion want, nor shall we need With dangerous expedition to invade Heav'n, whose high walls fear no assault or Siege, Or ambush from the Deep. What if we find Some easier enterprize? There is a place (If ancient and prophetic fame in Heav'n Err not) another World, the happy seat Of som new Race call'd MAN, about this time To be created like to us, though less In power and excellence, but favour'd more Of him who rules above; so was his will Pronounc'd among the Gods, and by an Oath, That shook Heav'ns whol circumference, confirm'd. Thither let us bend all our thoughts, to learn What creatures there inhabit, of what mould, Or substance, how endu'd, and what thir Power, And where thir weakness, how attempted best, By force or suttlety: Though Heav'n be shut, And Heav'ns high Arbitrator sit secure In his own strength, this place may lye expos'd The utmost border of his Kingdom, left To their defence who hold it: here perhaps Som advantagious act may be achiev'd By sudden onset, either with Hell fire To waste his whole Creation, or possess All as our own, and drive as we were driven, The punie habitants, or if not drive, Seduce them to our Party, that thir God May prove thir foe, and with repenting hand Abolish his own works. This would surpass Common revenge, and interrupt his joy In our Confusion, and our Joy upraise In his disturbance; when his darling Sons Hurl'd headlong to partake with us, shall curse Thir frail Originals, and faded bliss, Faded so soon. Advise if this be worth Attempting, or to sit in darkness here Hatching vain Empires. Thus BEELZEBUB Pleaded his devilish Counsel, first devis'd By SATAN, and in part propos'd: for whence, But from the Author of all ill could Spring So deep a malice, to confound the race Of mankind in one root, and Earth with Hell To mingle and involve, done all to spite The great Creatour? But thir spite still serves His glory to augment. The bold design Pleas'd highly those infernal States, and joy Sparkl'd in all thir eyes; with full assent They vote: whereat his speech he thus renews. Well have ye judg'd, well ended long debate, Synod of Gods, and like to what ye are, Great things resolv'd; which from the lowest deep Will once more lift us up, in spight of Fate, Neerer our ancient Seat; perhaps in view Of those bright confines, whence with neighbouring Arms And opportune excursion we may chance Re-enter Heav'n; or else in some milde Zone Dwell not unvisited of Heav'ns fair Light Secure, and at the brightning Orient beam Purge off this gloom; the soft delicious Air, To heal the scarr of these corrosive Fires Shall breath her balme. But first whom shall we send In search of this new world, whom shall we find Sufficient? who shall tempt with wandring feet The dark unbottom'd infinite Abyss And through the palpable obscure find out His uncouth way, or spread his aerie flight Upborn with indefatigable wings Over the vast abrupt, ere he arrive The happy Ile; what strength, what art can then Suffice, or what evasion bear him safe Through the strict Senteries and Stations thick Of Angels watching round? Here he had need All circumspection, and we now no less Choice in our suffrage; for on whom we send, The weight of all and our last hope relies. This said, he sat; and expectation held His look suspence, awaiting who appeer'd To second, or oppose, or undertake The perilous attempt: but all sat mute, Pondering the danger with deep thoughts; & each In others count'nance red his own dismay Astonisht: none among the choice and prime Of those Heav'n-warring Champions could be found So hardie as to proffer or accept Alone the dreadful voyage; till at last SATAN, whom now transcendent glory rais'd Above his fellows, with Monarchal pride Conscious of highest worth, unmov'd thus spake. O Progeny of Heav'n, Empyreal Thrones, With reason hath deep silence and demurr Seis'd us, though undismaid: long is the way And hard, that out of Hell leads up to Light; Our prison strong, this huge convex of Fire, Outrageous to devour, immures us round Ninefold, and gates of burning Adamant Barr'd over us prohibit all egress. These past, if any pass, the void profound Of unessential Night receives him next Wide gaping, and with utter loss of being Threatens him, plung'd in that abortive gulf. If thence he scape into what ever world, Or unknown Region, what remains him less Then unknown dangers and as hard escape. But I should ill become this Throne, O Peers, And this Imperial Sov'ranty, adorn'd With splendor, arm'd with power, if aught propos'd And judg'd of public moment, in the shape Of difficulty or danger could deterre Me from attempting. Wherefore do I assume These Royalties, and not refuse to Reign, Refusing to accept as great a share Of hazard as of honour, due alike To him who Reigns, and so much to him due Of hazard more, as he above the rest High honourd sits? Go therfore mighty powers, Terror of Heav'n, though fall'n; intend at home, While here shall be our home, what best may ease The present misery, and render Hell More tollerable; if there be cure or charm To respite or deceive, or slack the pain Of this ill Mansion: intermit no watch Against a wakeful Foe, while I abroad Through all the coasts of dark destruction seek Deliverance for us all: this enterprize None shall partake with me. Thus saying rose The Monarch, and prevented all reply, Prudent, least from his resolution rais'd Others among the chief might offer now (Certain to be refus'd) what erst they feard; And so refus'd might in opinion stand His rivals, winning cheap the high repute Which he through hazard huge must earn. But they Dreaded not more th' adventure then his voice Forbidding; and at once with him they rose; Thir rising all at once was as the sound Of Thunder heard remote. Towards him they bend With awful reverence prone; and as a God Extoll him equal to the highest in Heav'n: Nor fail'd they to express how much they prais'd, That for the general safety he despis'd His own: for neither do the Spirits damn'd Loose all thir vertue; least bad men should boast Thir specious deeds on earth, which glory excites, Or close ambition varnisht o're with zeal. Thus they thir doubtful consultations dark Ended rejoycing in thir matchless Chief: As when from mountain tops the dusky clouds Ascending, while the North wind sleeps, o'respread Heav'ns chearful face, the lowring Element Scowls ore the dark'nd lantskip Snow, or showre; If chance the radiant Sun with farewell sweet Extend his ev'ning beam, the fields revive, The birds thir notes renew, and bleating herds Attest thir joy, that hill and valley rings. O shame to men! Devil with Devil damn'd Firm concord holds, men onely disagree Of Creatures rational, though under hope Of heavenly Grace: and God proclaiming peace, Yet live in hatred, enmitie, and strife Among themselves, and levie cruel warres, Wasting the Earth, each other to destroy: As if (which might induce us to accord) Man had not hellish foes anow besides, That day and night for his destruction waite. The STYGIAN Councel thus dissolv'd; and forth In order came the grand infernal Peers, Midst came thir mighty Paramount, and seemd Alone th' Antagonist of Heav'n, nor less Then Hells dread Emperour with pomp Supream, And God-like imitated State; him round A Globe of fierie Seraphim inclos'd With bright imblazonrie, and horrent Arms. Then of thir Session ended they bid cry With Trumpets regal sound the great result: Toward the four winds four speedy Cherubim Put to thir mouths the sounding Alchymie By Haralds voice explain'd: the hollow Abyss Heard farr and wide, and all the host of Hell With deafning shout, return'd them loud acclaim. Thence more at ease thir minds and somwhat rais'd By false presumptuous hope, the ranged powers Disband, and wandring, each his several way Pursues, as inclination or sad choice Leads him perplext, where he may likeliest find Truce to his restless thoughts, and entertain The irksome hours, till his great Chief return. Part on the Plain, or in the Air sublime Upon the wing, or in swift race contend, As at th' Olympian Games or PYTHIAN fields; Part curb thir fierie Steeds, or shun the Goal With rapid wheels, or fronted Brigads form. As when to warn proud Cities warr appears Wag'd in the troubl'd Skie, and Armies rush To Battel in the Clouds, before each Van Pric forth the Aerie Knights, and couch thir spears Till thickest Legions close; with feats of Arms From either end of Heav'n the welkin burns. Others with vast TYPHOEAN rage more fell Rend up both Rocks and Hills, and ride the Air In whirlwind; Hell scarce holds the wilde uproar. As when ALCIDES from OEALIA Crown'd With conquest, felt th' envenom'd robe, and tore Through pain up by the roots THESSALIAN Pines, And LICHAS from the top of OETA threw Into th' EUBOIC Sea. Others more milde, Retreated in a silent valley, sing With notes Angelical to many a Harp Thir own Heroic deeds and hapless fall By doom of Battel; and complain that Fate Free Vertue should enthrall to Force or Chance. Thir song was partial, but the harmony (What could it less when Spirits immortal sing?) Suspended Hell, and took with ravishment The thronging audience. In discourse more sweet (For Eloquence the Soul, Song charms the Sense,) Others apart sat on a Hill retir'd, In thoughts more elevate, and reason'd high Of Providence, Foreknowledge, Will, and Fate, Fixt Fate, free will, foreknowledge absolute, And found no end, in wandring mazes lost. Of good and evil much they argu'd then, Of happiness and final misery, Passion and Apathie, and glory and shame, Vain wisdom all, and false Philosophie: Yet with a pleasing sorcerie could charm Pain for a while or anguish, and excite Fallacious hope, or arm th' obdured brest With stubborn patience as with triple steel. Another part in Squadrons and gross Bands, On bold adventure to discover wide That dismal world, if any Clime perhaps Might yeild them easier habitation, bend Four ways thir flying March, along the Banks Of four infernal Rivers that disgorge Into the burning Lake thir baleful streams; Abhorred STYX the flood of deadly hate, Sad ACHERON of sorrow, black and deep; COCYTUS, nam'd of lamentation loud Heard on the ruful stream; fierce PHLEGETON Whose waves of torrent fire inflame with rage. Farr off from these a slow and silent stream, LETHE the River of Oblivion roules Her watrie Labyrinth, whereof who drinks, Forthwith his former state and being forgets, Forgets both joy and grief, pleasure and pain. Beyond this flood a frozen Continent Lies dark and wilde, beat with perpetual storms Of Whirlwind and dire Hail, which on firm land Thaws not, but gathers heap, and ruin seems Of ancient pile; all else deep snow and ice, A gulf profound as that SERBONIAN Bog Betwixt DAMIATA and mount CASIUS old, Where Armies whole have sunk: the parching Air Burns frore, and cold performs th' effect of Fire. Thither by harpy-footed Furies hail'd, At certain revolutions all the damn'd Are brought: and feel by turns the bitter change Of fierce extreams, extreams by change more fierce, From Beds of raging Fire to starve in Ice Thir soft Ethereal warmth, and there to pine Immovable, infixt, and frozen round, Periods of time, thence hurried back to fire. They ferry over this LETHEAN Sound Both to and fro, thir sorrow to augment, And wish and struggle, as they pass, to reach The tempting stream, with one small drop to loose In sweet forgetfulness all pain and woe, All in one moment, and so neer the brink; But fate withstands, and to oppose th' attempt MEDUSA with GORGONIAN terror guards The Ford, and of it self the water flies All taste of living wight, as once it fled The lip of TANTALUS. Thus roving on In confus'd march forlorn, th' adventrous Bands With shuddring horror pale, and eyes agast View'd first thir lamentable lot, and found No rest: through many a dark and drearie Vaile They pass'd, and many a Region dolorous, O're many a Frozen, many a Fierie Alpe, Rocks, Caves, Lakes, Fens, Bogs, Dens, and shades of death, A Universe of death, which God by curse Created evil, for evil only good, Where all life dies, death lives, and nature breeds, Perverse, all monstrous, all prodigious things, Abominable, inutterable, and worse Then Fables yet have feign'd, or fear conceiv'd, GORGONS and HYDRA'S, and CHIMERA'S dire. Mean while the Adversary of God and Man, SATAN with thoughts inflam'd of highest design, Puts on swift wings, and toward the Gates of Hell Explores his solitary flight; som times He scours the right hand coast, som times the left, Now shaves with level wing the Deep, then soares Up to the fiery concave touring high. As when farr off at Sea a Fleet descri'd Hangs in the Clouds, by AEQUINOCTIAL Winds Close sailing from BENGALA, or the Iles Of TERNATE and TIDORE, whence Merchants bring Thir spicie Drugs: they on the trading Flood Through the wide ETHIOPIAN to the Cape Ply stemming nightly toward the Pole. So seem'd Farr off the flying Fiend: at last appeer Hell bounds high reaching to the horrid Roof, And thrice threefold the Gates; three folds were Brass Three Iron, three of Adamantine Rock, Impenitrable, impal'd with circling fire, Yet unconsum'd. Before the Gates there sat On either side a formidable shape; The one seem'd Woman to the waste, and fair, But ended foul in many a scaly fould Voluminous and vast, a Serpent arm'd With mortal sting: about her middle round A cry of Hell Hounds never ceasing bark'd With wide CERBEREAN mouths full loud, and rung A hideous Peal: yet, when they list, would creep, If aught disturb'd thir noyse, into her woomb, And kennel there, yet there still bark'd and howl'd Within unseen. Farr less abhorrd then these Vex'd SCYLLA bathing in the Sea that parts CALABRIA from the hoarce TRINACRIAN shore: Nor uglier follow the Night-Hag, when call'd In secret, riding through the Air she comes Lur'd with the smell of infant blood, to dance With LAPLAND Witches, while the labouring Moon Eclipses at thir charms. The other shape, If shape it might be call'd that shape had none Distinguishable in member, joynt, or limb, Or substance might be call'd that shadow seem'd, For each seem'd either; black it stood as Night, Fierce as ten Furies, terrible as Hell, And shook a dreadful Dart; what seem'd his head The likeness of a Kingly Crown had on. SATAN was now at hand, and from his seat The Monster moving onward came as fast, With horrid strides, Hell trembled as he strode. Th' undaunted Fiend what this might be admir'd, Admir'd, not fear'd; God and his Son except, Created thing naught vallu'd he nor shun'd; And with disdainful look thus first began. Whence and what art thou, execrable shape, That dar'st, though grim and terrible, advance Thy miscreated Front athwart my way To yonder Gates? through them I mean to pass, That be assur'd, without leave askt of thee: Retire, or taste thy folly, and learn by proof, Hell-born, not to contend with Spirits of Heav'n. To whom the Goblin full of wrauth reply'd, Art thou that Traitor Angel, art thou hee, Who first broke peace in Heav'n and Faith, till then Unbrok'n, and in proud rebellious Arms Drew after him the third part of Heav'ns Sons Conjur'd against the highest, for which both Thou And they outcast from God, are here condemn'd To waste Eternal daies in woe and pain? And reck'n'st thou thy self with Spirits of Heav'n, Hell-doomd, and breath'st defiance here and scorn, Where I reign King, and to enrage thee more, Thy King and Lord? Back to thy punishment, False fugitive, and to thy speed add wings, Least with a whip of Scorpions I pursue Thy lingring, or with one stroke of this Dart Strange horror seise thee, and pangs unfelt before. So spake the grieslie terrour, and in shape, So speaking and so threatning, grew ten fold More dreadful and deform: on th' other side Incenc't with indignation SATAN stood Unterrifi'd, and like a Comet burn'd, That fires the length of OPHIUCUS huge In th' Artick Sky, and from his horrid hair Shakes Pestilence and Warr. Each at the Head Level'd his deadly aime; thir fatall hands No second stroke intend, and such a frown Each cast at th' other, as when two black Clouds With Heav'ns Artillery fraught, come rattling on Over the CASPIAN, then stand front to front Hov'ring a space, till Winds the signal blow To joyn thir dark Encounter in mid air: So frownd the mighty Combatants, that Hell Grew darker at thir frown, so matcht they stood; For never but once more was either like To meet so great a foe: and now great deeds Had been achiev'd, whereof all Hell had rung, Had not the Snakie Sorceress that sat Fast by Hell Gate, and kept the fatal Key, Ris'n, and with hideous outcry rush'd between. O Father, what intends thy hand, she cry'd, Against thy only Son? What fury O Son, Possesses thee to bend that mortal Dart Against thy Fathers head? and know'st for whom; For him who sits above and laughs the while At thee ordain'd his drudge, to execute What e're his wrath, which he calls Justice, bids, His wrath which one day will destroy ye both. She spake, and at her words the hellish Pest Forbore, then these to her SATAN return'd: So strange thy outcry, and thy words so strange Thou interposest, that my sudden hand Prevented spares to tell thee yet by deeds What it intends; till first I know of thee, What thing thou art, thus double-form'd, and why In this infernal Vaile first met thou call'st Me Father, and that Fantasm call'st my Son? I know thee not, nor ever saw till now Sight more detestable then him and thee. T' whom thus the Portress of Hell Gate reply'd; Hast thou forgot me then, and do I seem Now in thine eye so foul, once deemd so fair In Heav'n, when at th' Assembly, and in sight Of all the Seraphim with thee combin'd In bold conspiracy against Heav'ns King, All on a sudden miserable pain Surpris'd thee, dim thine eyes, and dizzie swumm In darkness, while thy head flames thick and fast Threw forth, till on the left side op'ning wide, Likest to thee in shape and count'nance bright, Then shining heav'nly fair, a Goddess arm'd Out of thy head I sprung: amazement seis'd All th' Host of Heav'n; back they recoild affraid At first, and call'd me SIN, and for a Sign Portentous held me; but familiar grown, I pleas'd, and with attractive graces won The most averse, thee chiefly, who full oft Thy self in me thy perfect image viewing Becam'st enamour'd, and such joy thou took'st With me in secret, that my womb conceiv'd A growing burden. Mean while Warr arose, And fields were fought in Heav'n; wherein remaind (For what could else) to our Almighty Foe Cleer Victory, to our part loss and rout Through all the Empyrean: down they fell Driv'n headlong from the Pitch of Heaven, down Into this Deep, and in the general fall I also; at which time this powerful Key Into my hand was giv'n, with charge to keep These Gates for ever shut, which none can pass Without my op'ning. Pensive here I sat Alone, but long I sat not, till my womb Pregnant by thee, and now excessive grown Prodigious motion felt and rueful throes. At last this odious offspring whom thou seest Thine own begotten, breaking violent way Tore through my entrails, that with fear and pain Distorted, all my nether shape thus grew Transform'd: but he my inbred enemie Forth issu'd, brandishing his fatal Dart Made to destroy: I fled, and cry'd out DEATH; Hell trembl'd at the hideous Name, and sigh'd From all her Caves, and back resounded DEATH. I fled, but he pursu'd (though more, it seems, Inflam'd with lust then rage) and swifter far, Me overtook his mother all dismaid, And in embraces forcible and foule Ingendring with me, of that rape begot These yelling Monsters that with ceasless cry Surround me, as thou sawst, hourly conceiv'd And hourly born, with sorrow infinite To me, for when they list into the womb That bred them they return, and howle and gnaw My Bowels, their repast; then bursting forth Afresh with conscious terrours vex me round, That rest or intermission none I find. Before mine eyes in opposition sits Grim DEATH my Son and foe, who sets them on, And me his Parent would full soon devour For want of other prey, but that he knows His end with mine involvd; and knows that I Should prove a bitter Morsel, and his bane, When ever that shall be; so Fate pronounc'd. But thou O Father, I forewarn thee, shun His deadly arrow; neither vainly hope To be invulnerable in those bright Arms, Though temper'd heav'nly, for that mortal dint, Save he who reigns above, none can resist. She finish'd, and the suttle Fiend his lore Soon learnd, now milder, and thus answerd smooth. Dear Daughter, since thou claim'st me for thy Sire, And my fair Son here showst me, the dear pledge Of dalliance had with thee in Heav'n, and joys Then sweet, now sad to mention, through dire change Befalln us unforeseen, unthought of, know I come no enemie, but to set free From out this dark and dismal house of pain, Both him and thee, and all the heav'nly Host Of Spirits that in our just pretenses arm'd Fell with us from on high: from them I go This uncouth errand sole, and one for all My self expose, with lonely steps to tread Th' unfounded deep, & through the void immense To search with wandring quest a place foretold Should be, and, by concurring signs, ere now Created vast and round, a place of bliss In the Pourlieues of Heav'n, and therein plac't A race of upstart Creatures, to supply Perhaps our vacant room, though more remov'd, Least Heav'n surcharg'd with potent multitude Might hap to move new broiles: Be this or aught Then this more secret now design'd, I haste To know, and this once known, shall soon return, And bring ye to the place where Thou and Death Shall dwell at ease, and up and down unseen Wing silently the buxom Air, imbalm'd With odours; there ye shall be fed and fill'd Immeasurably, all things shall be your prey. He ceas'd, for both seemd highly pleasd, and Death Grinnd horrible a gastly smile, to hear His famine should be fill'd, and blest his mawe Destin'd to that good hour: no less rejoyc'd His mother bad, and thus bespake her Sire. The key of this infernal Pit by due, And by command of Heav'ns all-powerful King I keep, by him forbidden to unlock These Adamantine Gates; against all force Death ready stands to interpose his dart, Fearless to be o'rematcht by living might. But what ow I to his commands above Who hates me, and hath hither thrust me down Into this gloom of TARTARUS profound, To sit in hateful Office here confin'd, Inhabitant of Heav'n, and heav'nlie-born, Here in perpetual agonie and pain, With terrors and with clamors compasst round Of mine own brood, that on my bowels feed: Thou art my Father, thou my Author, thou My being gav'st me; whom should I obey But thee, whom follow? thou wilt bring me soon To that new world of light and bliss, among The Gods who live at ease, where I shall Reign At thy right hand voluptuous, as beseems Thy daughter and thy darling, without end. Thus saying, from her side the fatal Key, Sad instrument of all our woe, she took; And towards the Gate rouling her bestial train, Forthwith the huge Porcullis high up drew, Which but her self not all the STYGIAN powers Could once have mov'd; then in the key-hole turns Th' intricate wards, and every Bolt and Bar Of massie Iron or sollid Rock with ease Unfast'ns: on a sudden op'n flie With impetuous recoile and jarring sound Th' infernal dores, and on thir hinges great Harsh Thunder, that the lowest bottom shook Of EREBUS. She op'nd, but to shut Excel'd her power; the Gates wide op'n stood, That with extended wings a Bannerd Host Under spread Ensigns marching might pass through With Horse and Chariots rankt in loose array; So wide they stood, and like a Furnace mouth Cast forth redounding smoak and ruddy flame. Before thir eyes in sudden view appear The secrets of the hoarie deep, a dark Illimitable Ocean without bound, Without dimension, where length, breadth, and highth, And time and place are lost; where eldest Night And CHAOS, Ancestors of Nature, hold Eternal ANARCHIE, amidst the noise Of endless warrs and by confusion stand. For hot, cold, moist, and dry, four Champions fierce Strive here for Maistrie, and to Battel bring Thir embryon Atoms; they around the flag Of each his faction, in thir several Clanns, Light-arm'd or heavy, sharp, smooth, swift or slow, Swarm populous, unnumber'd as the Sands Of BARCA or CYRENE'S torrid soil, Levied to side with warring Winds, and poise Thir lighter wings. To whom these most adhere, Hee rules a moment; CHAOS Umpire sits, And by decision more imbroiles the fray By which he Reigns: next him high Arbiter CHANCE governs all. Into this wilde Abyss, The Womb of nature and perhaps her Grave, Of neither Sea, nor Shore, nor Air, nor Fire, But all these in thir pregnant causes mixt Confus'dly, and which thus must ever fight, Unless th' Almighty Maker them ordain His dark materials to create more Worlds, Into this wilde Abyss the warie fiend Stood on the brink of Hell and look'd a while, Pondering his Voyage; for no narrow frith He had to cross. Nor was his eare less peal'd With noises loud and ruinous (to compare Great things with small) then when BELLONA storms, With all her battering Engines bent to rase Som Capital City, or less then if this frame Of Heav'n were falling, and these Elements In mutinie had from her Axle torn The stedfast Earth. At last his Sail-broad Vannes He spreads for flight, and in the surging smoak Uplifted spurns the ground, thence many a League As in a cloudy Chair ascending rides Audacious, but that seat soon failing, meets A vast vacuitie: all unawares Fluttring his pennons vain plumb down he drops Ten thousand fadom deep, and to this hour Down had been falling, had not by ill chance The strong rebuff of som tumultuous cloud Instinct with Fire and Nitre hurried him As many miles aloft: that furie stay'd, Quencht in a Boggie SYRTIS, neither Sea, Nor good dry Land: nigh founderd on he fares, Treading the crude consistence, half on foot, Half flying; behoves him now both Oare and Saile. As when a Gryfon through the Wilderness With winged course ore Hill or moarie Dale, Pursues the ARIMASPIAN, who by stelth Had from his wakeful custody purloind The guarded Gold: So eagerly the fiend Ore bog or steep, through strait, rough, dense, or rare, With head, hands, wings, or feet pursues his way, And swims or sinks, or wades, or creeps, or flyes: At length a universal hubbub wilde Of stunning sounds and voices all confus'd Born through the hollow dark assaults his eare With loudest vehemence: thither he plyes, Undaunted to meet there what ever power Or Spirit of the nethermost Abyss Might in that noise reside, of whom to ask Which way the neerest coast of darkness lyes Bordering on light; when strait behold the Throne Of CHAOS, and his dark Pavilion spread Wide on the wasteful Deep; with him Enthron'd Sat Sable-vested Night, eldest of things, The consort of his Reign; and by them stood ORCUS and ADES, and the dreaded name Of DEMOGORGON; Rumor next and Chance, And Tumult and Confusion all imbroild, And Discord with a thousand various mouths. T' whom SATAN turning boldly, thus. Ye Powers And Spirits of this nethermost Abyss, CHAOS and ANCIENT NIGHT, I come no Spie, With purpose to explore or to disturb The secrets of your Realm, but by constraint Wandring this darksome desart, as my way Lies through your spacious Empire up to light, Alone, and without guide, half lost, I seek What readiest path leads where your gloomie bounds Confine with Heav'n; or if som other place From your Dominion won, th' Ethereal King Possesses lately, thither to arrive I travel this profound, direct my course; Directed, no mean recompence it brings To your behoof, if I that Region lost, All usurpation thence expell'd, reduce To her original darkness and your sway (Which is my present journey) and once more Erect the Standerd there of ANCIENT NIGHT; Yours be th' advantage all, mine the revenge. Thus SATAN; and him thus the Anarch old With faultring speech and visage incompos'd Answer'd. I know thee, stranger, who thou art, That mighty leading Angel, who of late Made head against Heav'ns King, though overthrown. I saw and heard, for such a numerous host Fled not in silence through the frighted deep With ruin upon ruin, rout on rout, Confusion worse confounded; and Heav'n Gates Pourd out by millions her victorious Bands Pursuing. I upon my Frontieres here Keep residence; if all I can will serve, That little which is left so to defend Encroacht on still through our intestine broiles Weakning the Scepter of old Night: first Hell Your dungeon stretching far and wide beneath; Now lately Heaven and Earth, another World Hung ore my Realm, link'd in a golden Chain To that side Heav'n from whence your Legions fell: If that way be your walk, you have not farr; So much the neerer danger; goe and speed; Havock and spoil and ruin are my gain. He ceas'd; and SATAN staid not to reply, But glad that now his Sea should find a shore, With fresh alacritie and force renew'd Springs upward like a Pyramid of fire Into the wilde expanse, and through the shock Of fighting Elements, on all sides round Environ'd wins his way; harder beset And more endanger'd, then when ARGO pass'd Through BOSPORUS betwixt the justling Rocks: Or when ULYSSES on the Larbord shunnd CHARYBDIS, and by th' other whirlpool steard. So he with difficulty and labour hard Mov'd on, with difficulty and labour hee; But hee once past, soon after when man fell, Strange alteration! Sin and Death amain Following his track, such was the will of Heav'n, Pav'd after him a broad and beat'n way Over the dark Abyss, whose boiling Gulf Tamely endur'd a Bridge of wondrous length From Hell continu'd reaching th' utmost Orbe Of this frail World; by which the Spirits perverse With easie intercourse pass to and fro To tempt or punish mortals, except whom God and good Angels guard by special grace. But now at last the sacred influence Of light appears, and from the walls of Heav'n Shoots farr into the bosom of dim Night A glimmering dawn; here Nature first begins Her fardest verge, and CHAOS to retire As from her outmost works a brok'n foe With tumult less and with less hostile din, That SATAN with less toil, and now with ease Wafts on the calmer wave by dubious light And like a weather-beaten Vessel holds Gladly the Port, though Shrouds and Tackle torn; Or in the emptier waste, resembling Air, Weighs his spread wings, at leasure to behold Farr off th' Empyreal Heav'n, extended wide In circuit, undetermind square or round, With Opal Towrs and Battlements adorn'd Of living Saphire, once his native Seat; And fast by hanging in a golden Chain This pendant world, in bigness as a Starr Of smallest Magnitude close by the Moon. Thither full fraught with mischievous revenge, Accurst, and in a cursed hour he hies. THE END OF THE SECOND BOOK. PARADISE LOST BOOK III HAil holy light, ofspring of Heav'n first-born, Or of th' Eternal Coeternal beam May I express thee unblam'd? since God is light, And never but in unapproached light Dwelt from Eternitie, dwelt then in thee, Bright effluence of bright essence increate. Or hear'st thou rather pure Ethereal stream, Whose Fountain who shall tell? before the Sun, Before the Heavens thou wert, and at the voice Of God, as with a Mantle didst invest The rising world of waters dark and deep, Won from the void and formless infinite. Thee I re-visit now with bolder wing, Escap't the STYGIAN Pool, though long detain'd In that obscure sojourn, while in my flight Through utter and through middle darkness borne With other notes then to th' ORPHEAN Lyre I sung of CHAOS and ETERNAL NIGHT, Taught by the heav'nly Muse to venture down The dark descent, and up to reascend, Though hard and rare: thee I revisit safe, And feel thy sovran vital Lamp; but thou Revisit'st not these eyes, that rowle in vain To find thy piercing ray, and find no dawn; So thick a drop serene hath quencht thir Orbs, Or dim suffusion veild. Yet not the more Cease I to wander where the Muses haunt Cleer Spring, or shadie Grove, or Sunnie Hill, Smit with the love of sacred song; but chief Thee SION and the flowrie Brooks beneath That wash thy hallowd feet, and warbling flow, Nightly I visit: nor somtimes forget Those other two equal'd with me in Fate, So were I equal'd with them in renown, Blind THAMYRIS and blind MAEONIDES, And TIRESIAS and PHINEUS Prophets old. Then feed on thoughts, that voluntarie move Harmonious numbers; as the wakeful Bird Sings darkling, and in shadiest Covert hid Tunes her nocturnal Note. Thus with the Year Seasons return, but not to me returns Day, or the sweet approach of Ev'n or Morn, Or sight of vernal bloom, or Summers Rose, Or flocks, or herds, or human face divine; But cloud in stead, and ever-during dark Surrounds me, from the chearful waies of men Cut off, and for the book of knowledg fair Presented with a Universal blanc Of Natures works to mee expung'd and ras'd, And wisdome at one entrance quite shut out. So much the rather thou Celestial light Shine inward, and the mind through all her powers Irradiate, there plant eyes, all mist from thence Purge and disperse, that I may see and tell Of things invisible to mortal sight. Now had the Almighty Father from above, From the pure Empyrean where he sits High Thron'd above all highth, bent down his eye, His own works and their works at once to view: About him all the Sanctities of Heaven Stood thick as Starrs, and from his sight receiv'd Beatitude past utterance; on his right The radiant image of his Glory sat, His onely Son; On Earth he first beheld Our two first Parents, yet the onely two Of mankind, in the happie Garden plac't, Reaping immortal fruits of joy and love, Uninterrupted joy, unrivald love In blissful solitude; he then survey'd Hell and the Gulf between, and SATAN there Coasting the wall of Heav'n on this side Night In the dun Air sublime, and ready now To stoop with wearied wings, and willing feet On the bare outside of this World, that seem'd Firm land imbosom'd without Firmament, Uncertain which, in Ocean or in Air. Him God beholding from his prospect high, Wherein past, present, future he beholds, Thus to his onely Son foreseeing spake. Onely begotten Son, seest thou what rage Transports our adversarie, whom no bounds Prescrib'd, no barrs of Hell, nor all the chains Heapt on him there, nor yet the main Abyss Wide interrupt can hold; so bent he seems On desperat revenge, that shall redound Upon his own rebellious head. And now Through all restraint broke loose he wings his way Not farr off Heav'n, in the Precincts of light, Directly towards the new created World, And Man there plac't, with purpose to assay If him by force he can destroy, or worse, By som false guile pervert; and shall pervert; For man will heark'n to his glozing lyes, And easily transgress the sole Command, Sole pledge of his obedience: So will fall Hee and his faithless Progenie: whose fault? Whose but his own? ingrate, he had of mee All he could have; I made him just and right, Sufficient to have stood, though free to fall. Such I created all th' Ethereal Powers And Spirits, both them who stood & them who faild; Freely they stood who stood, and fell who fell. Not free, what proof could they have givn sincere Of true allegiance, constant Faith or Love, Where onely what they needs must do, appeard, Not what they would? what praise could they receive? What pleasure I from such obedience paid, When Will and Reason (Reason also is choice) Useless and vain, of freedom both despoild, Made passive both, had servd necessitie, Not mee. They therefore as to right belongd, So were created, nor can justly accuse Thir maker, or thir making, or thir Fate; As if Predestination over-rul'd Thir will, dispos'd by absolute Decree Or high foreknowledge; they themselves decreed Thir own revolt, not I: if I foreknew, Foreknowledge had no influence on their fault, Which had no less prov'd certain unforeknown. So without least impulse or shadow of Fate, Or aught by me immutablie foreseen, They trespass, Authors to themselves in all Both what they judge and what they choose; for so I formd them free, and free they must remain, Till they enthrall themselves: I else must change Thir nature, and revoke the high Decree Unchangeable, Eternal, which ordain'd Thir freedom, they themselves ordain'd thir fall. The first sort by thir own suggestion fell, Self-tempted, self-deprav'd: Man falls deceiv'd By the other first: Man therefore shall find grace, The other none: in Mercy and Justice both, Through Heav'n and Earth, so shall my glorie excel, But Mercy first and last shall brightest shine. Thus while God spake, ambrosial fragrance fill'd All Heav'n, and in the blessed Spirits elect Sense of new joy ineffable diffus'd: Beyond compare the Son of God was seen Most glorious, in him all his Father shon Substantially express'd, and in his face Divine compassion visibly appeerd, Love without end, and without measure Grace, Which uttering thus he to his Father spake. O Father, gracious was that word which clos'd Thy sovran sentence, that Man should find grace; For which both Heav'n and Earth shall high extoll Thy praises, with th' innumerable sound Of Hymns and sacred Songs, wherewith thy Throne Encompass'd shall resound thee ever blest. For should Man finally be lost, should Man Thy creature late so lov'd, thy youngest Son Fall circumvented thus by fraud, though joynd With his own folly? that be from thee farr, That farr be from thee, Father, who art Judge Of all things made, and judgest onely right. Or shall the Adversarie thus obtain His end, and frustrate thine, shall he fulfill His malice, and thy goodness bring to naught, Or proud return though to his heavier doom, Yet with revenge accomplish't and to Hell Draw after him the whole Race of mankind, By him corrupted? or wilt thou thy self Abolish thy Creation, and unmake, For him, what for thy glorie thou hast made? So should thy goodness and thy greatness both Be questiond and blaspheam'd without defence. To whom the great Creatour thus reply'd. O Son, in whom my Soul hath chief delight, Son of my bosom, Son who art alone My word, my wisdom, and effectual might, All hast thou spok'n as my thoughts are, all As my Eternal purpose hath decreed: Man shall not quite be lost, but sav'd who will, Yet not of will in him, but grace in me Freely voutsaft; once more I will renew His lapsed powers, though forfeit and enthrall'd By sin to foul exorbitant desires; Upheld by me, yet once more he shall stand On even ground against his mortal foe, By me upheld, that he may know how frail His fall'n condition is, and to me ow All his deliv'rance, and to none but me. Some I have chosen of peculiar grace Elect above the rest; so is my will: The rest shall hear me call, and oft be warnd Thir sinful state, and to appease betimes Th' incensed Deitie, while offerd grace Invites; for I will cleer thir senses dark, What may suffice, and soft'n stonie hearts To pray, repent, and bring obedience due. To prayer, repentance, and obedience due, Though but endevord with sincere intent, Mine eare shall not be slow, mine eye not shut. And I will place within them as a guide My Umpire CONSCIENCE, whom if they will hear, Light after light well us'd they shall attain, And to the end persisting, safe arrive. This my long sufferance and my day of grace They who neglect and scorn, shall never taste; But hard be hard'nd, blind be blinded more, That they may stumble on, and deeper fall; And none but such from mercy I exclude. But yet all is not don; Man disobeying, Disloyal breaks his fealtie, and sinns Against the high Supremacie of Heav'n, Affecting God-head, and so loosing all, To expiate his Treason hath naught left, But to destruction sacred and devote, He with his whole posteritie must die, Die hee or Justice must; unless for him Som other able, and as willing, pay The rigid satisfaction, death for death. Say Heav'nly Powers, where shall we find such love, Which of ye will be mortal to redeem Mans mortal crime, and just th' unjust to save, Dwels in all Heaven charitie so deare? He ask'd, but all the Heav'nly Quire stood mute, And silence was in Heav'n: on mans behalf Patron or Intercessor none appeerd, Much less that durst upon his own head draw The deadly forfeiture, and ransom set. And now without redemption all mankind Must have bin lost, adjudg'd to Death and Hell By doom severe, had not the Son of God, In whom the fulness dwels of love divine, His dearest mediation thus renewd. Father, thy word is past, man shall find grace; And shall grace not find means, that finds her way, The speediest of thy winged messengers, To visit all thy creatures, and to all Comes unprevented, unimplor'd, unsought, Happie for man, so coming; he her aide Can never seek, once dead in sins and lost; Attonement for himself or offering meet, Indebted and undon, hath none to bring: Behold mee then, mee for him, life for life I offer, on mee let thine anger fall; Account mee man; I for his sake will leave Thy bosom, and this glorie next to thee Freely put off, and for him lastly die Well pleas'd, on me let Death wreck all his rage; Under his gloomie power I shall not long Lie vanquisht; thou hast givn me to possess Life in my self for ever, by thee I live, Though now to Death I yeild, and am his due All that of me can die, yet that debt paid, Thou wilt not leave me in the loathsom grave His prey, nor suffer my unspotted Soule For ever with corruption there to dwell; But I shall rise Victorious, and subdue My Vanquisher, spoild of his vanted spoile; Death his deaths wound shall then receive, & stoop Inglorious, of his mortall sting disarm'd. I through the ample Air in Triumph high Shall lead Hell Captive maugre Hell, and show The powers of darkness bound. Thou at the sight Pleas'd, out of Heaven shalt look down and smile, While by thee rais'd I ruin all my Foes, Death last, and with his Carcass glut the Grave: Then with the multitude of my redeemd Shall enter Heaven long absent, and returne, Father, to see thy face, wherein no cloud Of anger shall remain, but peace assur'd, And reconcilement; wrauth shall be no more Thenceforth, but in thy presence Joy entire. His words here ended, but his meek aspect Silent yet spake, and breath'd immortal love To mortal men, above which only shon Filial obedience: as a sacrifice Glad to be offer'd, he attends the will Of his great Father. Admiration seis'd All Heav'n, what this might mean, & whither tend Wondring; but soon th' Almighty thus reply'd: O thou in Heav'n and Earth the only peace Found out for mankind under wrauth, O thou My sole complacence! well thou know'st how dear, To me are all my works, nor Man the least Though last created, that for him I spare Thee from my bosom and right hand, to save, By loosing thee a while, the whole Race lost. Thou therefore whom thou only canst redeeme, Thir Nature also to thy Nature joyne; And be thy self Man among men on Earth, Made flesh, when time shall be, of Virgin seed, By wondrous birth: Be thou in ADAMS room The Head of all mankind, though ADAMS Son. As in him perish all men, so in thee As from a second root shall be restor'd, As many as are restor'd, without thee none. His crime makes guiltie all his Sons, thy merit Imputed shall absolve them who renounce Thir own both righteous and unrighteous deeds, And live in thee transplanted, and from thee Receive new life. So Man, as is most just, Shall satisfie for Man, be judg'd and die, And dying rise, and rising with him raise His Brethren, ransomd with his own dear life. So Heav'nly love shal outdoo Hellish hate, Giving to death, and dying to redeeme, So dearly to redeem what Hellish hate So easily destroy'd, and still destroyes In those who, when they may, accept not grace. Nor shalt thou by descending to assume Mans Nature, less'n or degrade thine owne. Because thou hast, though Thron'd in highest bliss Equal to God, and equally enjoying God-like fruition, quitted all to save A World from utter loss, and hast been found By Merit more then Birthright Son of God, Found worthiest to be so by being Good, Farr more then Great or High; because in thee Love hath abounded more then Glory abounds, Therefore thy Humiliation shall exalt With thee thy Manhood also to this Throne; Here shalt thou sit incarnate, here shalt Reigne Both God and Man, Son both of God and Man, Anointed universal King; all Power I give thee, reign for ever, and assume Thy Merits; under thee as Head Supream Thrones, Princedoms, Powers, Dominions I reduce: All knees to thee shall bow, of them that bide In Heaven, or Earth, or under Earth in Hell; When thou attended gloriously from Heav'n Shalt in the Skie appeer, and from thee send The summoning Arch-Angels to proclaime Thy dread Tribunal: forthwith from all Windes The living, and forthwith the cited dead Of all past Ages to the general Doom Shall hast'n, such a peal shall rouse thir sleep. Then all thy Saints assembl'd, thou shalt judge Bad men and Angels, they arraignd shall sink Beneath thy Sentence; Hell, her numbers full, Thenceforth shall be for ever shut. Mean while The World shall burn, and from her ashes spring New Heav'n and Earth, wherein the just shall dwell And after all thir tribulations long See golden days, fruitful of golden deeds, With Joy and Love triumphing, and fair Truth. Then thou thy regal Scepter shalt lay by, For regal Scepter then no more shall need, God shall be All in All. But all ye Gods, Adore him, who to compass all this dies, Adore the Son, and honour him as mee. No sooner had th' Almighty ceas't, but all The multitude of Angels with a shout Loud as from numbers without number, sweet As from blest voices, uttering joy, Heav'n rung With Jubilee, and loud Hosanna's fill'd Th' eternal Regions: lowly reverent Towards either Throne they bow, & to the ground With solemn adoration down they cast Thir Crowns inwove with Amarant and Gold, Immortal Amarant, a Flour which once In Paradise, fast by the Tree of Life Began to bloom, but soon for mans offence To Heav'n remov'd where first it grew, there grows, And flours aloft shading the Fount of Life, And where the river of Bliss through midst of Heavn Rowls o're ELISIAN Flours her Amber stream; With these that never fade the Spirits Elect Bind thir resplendent locks inwreath'd with beams, Now in loose Garlands thick thrown off, the bright Pavement that like a Sea of Jasper shon Impurpl'd with Celestial Roses smil'd. Then Crown'd again thir gold'n Harps they took, Harps ever tun'd, that glittering by their side Like Quivers hung, and with Praeamble sweet Of charming symphonie they introduce Thir sacred Song, and waken raptures high; No voice exempt, no voice but well could joine Melodious part, such concord is in Heav'n. Thee Father first they sung Omnipotent, Immutable, Immortal, Infinite, Eternal King; thee Author of all being, Fountain of Light, thy self invisible Amidst the glorious brightness where thou sit'st Thron'd inaccessible, but when thou shad'st The full blaze of thy beams, and through a cloud Drawn round about thee like a radiant Shrine, Dark with excessive bright thy skirts appeer, Yet dazle Heav'n, that brightest Seraphim Approach not, but with both wings veil thir eyes. Thee next they sang of all Creation first, Begotten Son, Divine Similitude, In whose conspicuous count'nance, without cloud Made visible, th' Almighty Father shines, Whom else no Creature can behold; on thee Impresst the effulgence of his Glorie abides, Transfus'd on thee his ample Spirit rests. Hee Heav'n of Heavens and all the Powers therein By thee created, and by thee threw down Th' aspiring Dominations: thou that day Thy Fathers dreadful Thunder didst not spare, Nor stop thy flaming Chariot wheels, that shook Heav'ns everlasting Frame, while o're the necks Thou drov'st of warring Angels disarraid. Back from pursuit thy Powers with loud acclaime Thee only extold, Son of thy Fathers might, To execute fierce vengeance on his foes, Not so on Man; him through their malice fall'n, Father of Mercie and Grace, thou didst not doome So strictly, but much more to pitie encline: No sooner did thy dear and onely Son Perceive thee purpos'd not to doom frail Man So strictly, but much more to pitie enclin'd, He to appease thy wrauth, and end the strife Of Mercy and Justice in thy face discern'd, Regardless of the Bliss wherein hee sat Second to thee, offerd himself to die For mans offence. O unexampl'd love, Love no where to be found less then Divine! Hail Son of God, Saviour of Men, thy Name Shall be the copious matter of my Song Henceforth, and never shall my Harp thy praise Forget, nor from thy Fathers praise disjoine. Thus they in Heav'n, above the starry Sphear, Thir happie hours in joy and hymning spent. Mean while upon the firm opacous Globe Of this round World, whose first convex divides The luminous inferior Orbs, enclos'd From CHAOS and th' inroad of Darkness old, SATAN alighted walks: a Globe farr off It seem'd, now seems a boundless Continent Dark, waste, and wild, under the frown of Night Starless expos'd, and ever-threatning storms Of CHAOS blustring round, inclement skie; Save on that side which from the wall of Heav'n Though distant farr som small reflection gaines Of glimmering air less vext with tempest loud: Here walk'd the Fiend at large in spacious field. As when a Vultur on IMAUS bred, Whose snowie ridge the roving TARTAR bounds, Dislodging from a Region scarce of prey To gorge the flesh of Lambs or yeanling Kids On Hills where Flocks are fed, flies toward the Springs Of GANGES or HYDASPES, INDIAN streams; But in his way lights on the barren plaines Of SERICANA, where CHINESES drive With Sails and Wind thir canie Waggons light: So on this windie Sea of Land, the Fiend Walk'd up and down alone bent on his prey, Alone, for other Creature in this place Living or liveless to be found was none, None yet, but store hereafter from the earth Up hither like Aereal vapours flew Of all things transitorie and vain, when Sin With vanity had filld the works of men: Both all things vain, and all who in vain things Built thir fond hopes of Glorie or lasting fame, Or happiness in this or th' other life; All who have thir reward on Earth, the fruits Of painful Superstition and blind Zeal, Naught seeking but the praise of men, here find Fit retribution, emptie as thir deeds; All th' unaccomplisht works of Natures hand, Abortive, monstrous, or unkindly mixt, Dissolvd on earth, fleet hither, and in vain, Till final dissolution, wander here, Not in the neighbouring Moon, as some have dreamd; Those argent Fields more likely habitants, Translated Saints, or middle Spirits hold Betwixt th' Angelical and Human kinde: Hither of ill-joynd Sons and Daughters born First from the ancient World those Giants came With many a vain exploit, though then renownd: The builders next of BABEL on the Plain Of SENNAAR, and still with vain designe New BABELS, had they wherewithall, would build: Others came single; hee who to be deemd A God, leap'd fondly into AETNA flames, EMPEDOCLES, and hee who to enjoy PLATO'S ELYSIUM, leap'd into the Sea, CLEOMBROTUS, and many more too long, Embryo's and Idiots, Eremits and Friers White, Black and Grey, with all thir trumperie. Here Pilgrims roam, that stray'd so farr to seek In GOLGOTHA him dead, who lives in Heav'n; And they who to be sure of Paradise Dying put on the weeds of DOMINIC, Or in FRANCISCAN think to pass disguis'd; They pass the Planets seven, and pass the fixt, And that Crystalline Sphear whose ballance weighs The Trepidation talkt, and that first mov'd; And now Saint PETER at Heav'ns Wicket seems To wait them with his Keys, and now at foot Of Heav'ns ascent they lift thir Feet, when loe A violent cross wind from either Coast Blows them transverse ten thousand Leagues awry Into the devious Air; then might ye see Cowles, Hoods and Habits with thir wearers tost And flutterd into Raggs, then Reliques, Beads, Indulgences, Dispenses, Pardons, Bulls, The sport of Winds: all these upwhirld aloft Fly o're the backside of the World farr off Into a LIMBO large and broad, since calld The Paradise of Fools, to few unknown Long after, now unpeopl'd, and untrod; All this dark Globe the Fiend found as he pass'd, And long he wanderd, till at last a gleame Of dawning light turnd thither-ward in haste His travell'd steps; farr distant hee descries Ascending by degrees magnificent Up to the wall of Heaven a Structure high, At top whereof, but farr more rich appeerd The work as of a Kingly Palace Gate With Frontispice of Diamond and Gold Imbellisht, thick with sparkling orient Gemmes The Portal shon, inimitable on Earth By Model, or by shading Pencil drawn. The Stairs were such as whereon JACOB saw Angels ascending and descending, bands Of Guardians bright, when he from ESAU fled To PADAN-ARAM in the field of LUZ, Dreaming by night under the open Skie, And waking cri'd, This is the Gate of Heav'n. Each Stair mysteriously was meant, nor stood There alwaies, but drawn up to Heav'n somtimes Viewless, and underneath a bright Sea flow'd Of Jasper, or of liquid Pearle, whereon Who after came from Earth, sayling arriv'd, Wafted by Angels, or flew o're the Lake Rapt in a Chariot drawn by fiery Steeds. The Stairs were then let down, whether to dare The Fiend by easie ascent, or aggravate His sad exclusion from the dores of Bliss. Direct against which op'nd from beneath, Just o're the blissful seat of Paradise, A passage down to th' Earth, a passage wide, Wider by farr then that of after-times Over Mount SION, and, though that were large, Over the PROMIS'D LAND to God so dear, By which, to visit oft those happy Tribes, On high behests his Angels to and fro Pass'd frequent, and his eye with choice regard From PANEAS the fount of JORDANS flood To BEERSABA, where the HOLY LAND Borders on AEGYPT and the ARABIAN shoare; So wide the op'ning seemd, where bounds were set To darkness, such as bound the Ocean wave. SATAN from hence now on the lower stair That scal'd by steps of Gold to Heav'n Gate Looks down with wonder at the sudden view Of all this World at once. As when a Scout Through dark and desart wayes with peril gone All night; at last by break of chearful dawne Obtains the brow of some high-climbing Hill, Which to his eye discovers unaware The goodly prospect of some forein land First-seen, or some renownd Metropolis With glistering Spires and Pinnacles adornd, Which now the Rising Sun guilds with his beams. Such wonder seis'd, though after Heaven seen, The Spirit maligne, but much more envy seis'd At sight of all this World beheld so faire. Round he surveys, and well might, where he stood So high above the circling Canopie Of Nights extended shade; from Eastern Point Of LIBRA to the fleecie Starr that bears ANDROMEDA farr off ATLANTICK Seas Beyond th' HORIZON; then from Pole to Pole He views in bredth, and without longer pause Down right into the Worlds first Region throws His flight precipitant, and windes with ease Through the pure marble Air his oblique way Amongst innumerable Starrs, that shon Stars distant, but nigh hand seemd other Worlds, Or other Worlds they seemd, or happy Iles, Like those HESPERIAN Gardens fam'd of old, Fortunate Fields, and Groves and flourie Vales, Thrice happy Iles, but who dwelt happy there He stayd not to enquire: above them all The golden Sun in splendor likest Heaven Allur'd his eye: Thither his course he bends Through the calm Firmament; but up or downe By center, or eccentric, hard to tell, Or Longitude, where the great Luminarie Alooff the vulgar Constellations thick, That from his Lordly eye keep distance due, Dispenses Light from farr; they as they move Thir Starry dance in numbers that compute Days, months, and years, towards his all-chearing Lamp Turn swift their various motions, or are turnd By his Magnetic beam, that gently warms The Univers, and to each inward part With gentle penetration, though unseen, Shoots invisible vertue even to the deep: So wondrously was set his Station bright. There lands the Fiend, a spot like which perhaps Astronomer in the Sun's lucent Orbe Through his glaz'd Optic Tube yet never saw. The place he found beyond expression bright, Compar'd with aught on Earth, Medal or Stone; Not all parts like, but all alike informd With radiant light, as glowing Iron with fire; If mettal, part seemd Gold, part Silver cleer; If stone, Carbuncle most or Chrysolite, Rubie or Topaz, to the Twelve that shon In AARONS Brest-plate, and a stone besides Imagind rather oft then elsewhere seen, That stone, or like to that which here below Philosophers in vain so long have sought, In vain, though by thir powerful Art they binde Volatil HERMES, and call up unbound In various shapes old PROTEUS from the Sea, Draind through a Limbec to his Native forme. What wonder then if fields and regions here Breathe forth ELIXIR pure, and Rivers run Potable Gold, when with one vertuous touch Th' Arch-chimic Sun so farr from us remote Produces with Terrestrial Humor mixt Here in the dark so many precious things Of colour glorious and effect so rare? Here matter new to gaze the Devil met Undazl'd, farr and wide his eye commands, For sight no obstacle found here, nor shade, But all Sun-shine, as when his Beams at Noon Culminate from th' AEQUATOR, as they now Shot upward still direct, whence no way round Shadow from body opaque can fall, and the Aire, No where so cleer, sharp'nd his visual ray To objects distant farr, whereby he soon Saw within kenn a glorious Angel stand, The same whom JOHN saw also in the Sun: His back was turnd, but not his brightness hid; Of beaming sunnie Raies, a golden tiar Circl'd his Head, nor less his Locks behind Illustrious on his Shoulders fledge with wings Lay waving round; on som great charge imploy'd Hee seemd, or fixt in cogitation deep. Glad was the Spirit impure as now in hope To find who might direct his wandring flight To Paradise the happie seat of Man, His journies end and our beginning woe. But first he casts to change his proper shape, Which else might work him danger or delay: And now a stripling Cherube he appeers, Not of the prime, yet such as in his face Youth smil'd Celestial, and to every Limb Sutable grace diffus'd, so well he feignd; Under a Coronet his flowing haire In curles on either cheek plaid, wings he wore Of many a colourd plume sprinkl'd with Gold, His habit fit for speed succinct, and held Before his decent steps a Silver wand. He drew not nigh unheard, the Angel bright, Ere he drew nigh, his radiant visage turnd, Admonisht by his eare, and strait was known Th' Arch-Angel URIEL, one of the seav'n Who in Gods presence, neerest to his Throne Stand ready at command, and are his Eyes That run through all the Heav'ns, or down to th' Earth Bear his swift errands over moist and dry, O're Sea and Land: him SATAN thus accostes; URIEL, for thou of those seav'n Spirits that stand In sight of God's high Throne, gloriously bright, The first art wont his great authentic will Interpreter through highest Heav'n to bring, Where all his Sons thy Embassie attend; And here art likeliest by supream decree Like honour to obtain, and as his Eye To visit oft this new Creation round; Unspeakable desire to see, and know All these his wondrous works, but chiefly Man, His chief delight and favour, him for whom All these his works so wondrous he ordaind, Hath brought me from the Quires of Cherubim Alone thus wandring. Brightest Seraph tell In which of all these shining Orbes hath Man His fixed seat, or fixed seat hath none, But all these shining Orbes his choice to dwell; That I may find him, and with secret gaze, Or open admiration him behold On whom the great Creator hath bestowd Worlds, and on whom hath all these graces powrd; That both in him and all things, as is meet, The Universal Maker we may praise; Who justly hath drivn out his Rebell Foes To deepest Hell, and to repair that loss Created this new happie Race of Men To serve him better: wise are all his wayes. So spake the false dissembler unperceivd; For neither Man nor Angel can discern Hypocrisie, the only evil that walks Invisible, except to God alone, By his permissive will, through Heav'n and Earth: And oft though wisdom wake, suspicion sleeps At wisdoms Gate, and to simplicitie Resigns her charge, while goodness thinks no ill Where no ill seems: Which now for once beguil'd URIEL, though Regent of the Sun, and held The sharpest sighted Spirit of all in Heav'n; Who to the fraudulent Impostor foule In his uprightness answer thus returnd. Faire Angel, thy desire which tends to know The works of God, thereby to glorifie The great Work-Maister, leads to no excess That reaches blame, but rather merits praise The more it seems excess, that led thee hither From thy Empyreal Mansion thus alone, To witness with thine eyes what some perhaps Contented with report heare onely in heav'n: For wonderful indeed are all his works, Pleasant to know, and worthiest to be all Had in remembrance alwayes with delight; But what created mind can comprehend Thir number, or the wisdom infinite That brought them forth, but hid thir causes deep. I saw when at his Word the formless Mass, This worlds material mould, came to a heap: Confusion heard his voice, and wilde uproar Stood rul'd, stood vast infinitude confin'd; Till at his second bidding darkness fled, Light shon, and order from disorder sprung: Swift to thir several Quarters hasted then The cumbrous Elements, Earth, Flood, Aire, Fire, And this Ethereal quintessence of Heav'n Flew upward, spirited with various forms, That rowld orbicular, and turnd to Starrs Numberless, as thou seest, and how they move; Each had his place appointed, each his course, The rest in circuit walles this Universe. Look downward on that Globe whose hither side With light from hence, though but reflected, shines; That place is Earth the seat of Man, that light His day, which else as th' other Hemisphere Night would invade, but there the neighbouring Moon (So call that opposite fair Starr) her aide Timely interposes, and her monthly round Still ending, still renewing, through mid Heav'n; With borrowd light her countenance triform Hence fills and empties to enlighten th' Earth, And in her pale dominion checks the night. That spot to which I point is PARADISE, ADAMS abode, those loftie shades his Bowre. Thy way thou canst not miss, me mine requires. Thus said, he turnd, and SATAN bowing low, As to superior Spirits is wont in Heaven, Where honour due and reverence none neglects, Took leave, and toward the coast of Earth beneath, Down from th' Ecliptic, sped with hop'd success, Throws his steep flight with many an Aerie wheele, Nor staid, till on NIPHATES top he lights. THE END OF THE THIRD BOOK. PARADISE LOST BOOK IV. O For that warning voice, which he who saw Th' APOCALYPS, heard cry in Heaven aloud, Then when the Dragon, put to second rout, Came furious down to be reveng'd on men, WO TO THE INHABITANTS ON EARTH! that now, While time was, our first Parents had bin warnd The coming of thir secret foe, and scap'd Haply so scap'd his mortal snare; for now SATAN, now first inflam'd with rage, came down, The Tempter ere th' Accuser of man-kind, To wreck on innocent frail man his loss Of that first Battel, and his flight to Hell: Yet not rejoycing in his speed, though bold, Far off and fearless, nor with cause to boast, Begins his dire attempt, which nigh the birth Now rowling, boiles in his tumultuous brest, And like a devillish Engine back recoiles Upon himself; horror and doubt distract His troubl'd thoughts, and from the bottom stirr The Hell within him, for within him Hell He brings, and round about him, nor from Hell One step no more then from himself can fly By change of place: Now conscience wakes despair That slumberd, wakes the bitter memorie Of what he was, what is, and what must be Worse; of worse deeds worse sufferings must ensue. Sometimes towards EDEN which now in his view Lay pleasant, his grievd look he fixes sad, Sometimes towards Heav'n and the full-blazing Sun, Which now sat high in his Meridian Towre: Then much revolving, thus in sighs began. O thou that with surpassing Glory crownd, Look'st from thy sole Dominion like the God Of this new World; at whose sight all the Starrs Hide thir diminisht heads; to thee I call, But with no friendly voice, and add thy name O Sun, to tell thee how I hate thy beams That bring to my remembrance from what state I fell, how glorious once above thy Spheare; Till Pride and worse Ambition threw me down Warring in Heav'n against Heav'ns matchless King: Ah wherefore! he deservd no such return From me, whom he created what I was In that bright eminence, and with his good Upbraided none; nor was his service hard. What could be less then to afford him praise, The easiest recompence, and pay him thanks, How due! yet all his good prov'd ill in me, And wrought but malice; lifted up so high I sdeind subjection, and thought one step higher Would set me highest, and in a moment quit The debt immense of endless gratitude, So burthensome, still paying, still to ow; Forgetful what from him I still receivd, And understood not that a grateful mind By owing owes not, but still pays, at once Indebted and dischargd; what burden then? O had his powerful Destiny ordaind Me some inferiour Angel, I had stood Then happie; no unbounded hope had rais'd Ambition. Yet why not? som other Power As great might have aspir'd, and me though mean Drawn to his part; but other Powers as great Fell not, but stand unshak'n, from within Or from without, to all temptations arm'd. Hadst thou the same free Will and Power to stand? Thou hadst: whom hast thou then or what to accuse, But Heav'ns free Love dealt equally to all? Be then his Love accurst, since love or hate, To me alike, it deals eternal woe. Nay curs'd be thou; since against his thy will Chose freely what it now so justly rues. Me miserable! which way shall I flie Infinite wrauth, and infinite despaire? Which way I flie is Hell; my self am Hell; And in the lowest deep a lower deep Still threatning to devour me opens wide, To which the Hell I suffer seems a Heav'n. O then at last relent: is there no place Left for Repentance, none for Pardon left? None left but by submission; and that word DISDAIN forbids me, and my dread of shame Among the spirits beneath, whom I seduc'd With other promises and other vaunts Then to submit, boasting I could subdue Th' Omnipotent. Ay me, they little know How dearly I abide that boast so vaine, Under what torments inwardly I groane; While they adore me on the Throne of Hell, With Diadem and Scepter high advanc'd The lower still I fall, onely Supream In miserie; such joy Ambition findes. But say I could repent and could obtaine By Act of Grace my former state; how soon Would highth recal high thoughts, how soon unsay What feign'd submission swore: ease would recant Vows made in pain, as violent and void. For never can true reconcilement grow Where wounds of deadly hate have peirc'd so deep: Which would but lead me to a worse relapse And heavier fall: so should I purchase deare Short intermission bought with double smart. This knows my punisher; therefore as farr From granting hee, as I from begging peace: All hope excluded thus, behold in stead Of us out-cast, exil'd, his new delight, Mankind created, and for him this World. So farwel Hope, and with Hope farwel Fear, Farwel Remorse: all Good to me is lost; Evil be thou my Good; by thee at least Divided Empire with Heav'ns King I hold By thee, and more then half perhaps will reigne; As Man ere long, and this new World shall know. Thus while he spake, each passion dimm'd his face Thrice chang'd with pale, ire, envie and despair, Which marrd his borrow'd visage, and betraid Him counterfet, if any eye beheld. For heav'nly mindes from such distempers foule Are ever cleer. Whereof hee soon aware, Each perturbation smooth'd with outward calme, Artificer of fraud; and was the first That practisd falshood under saintly shew, Deep malice to conceale, couch't with revenge: Yet not anough had practisd to deceive URIEL once warnd; whose eye pursu'd him down The way he went, and on th' ASSYRIAN mount Saw him disfigur'd, more then could befall Spirit of happie sort: his gestures fierce He markd and mad demeanour, then alone, As he suppos'd, all unobserv'd, unseen. So on he fares, and to the border comes Of EDEN, where delicious Paradise, Now nearer, Crowns with her enclosure green, As with a rural mound the champain head Of a steep wilderness, whose hairie sides With thicket overgrown, grottesque and wilde, Access deni'd; and over head up grew Insuperable highth of loftiest shade, Cedar, and Pine, and Firr, and branching Palm, A Silvan Scene, and as the ranks ascend Shade above shade, a woodie Theatre Of stateliest view. Yet higher then thir tops The verdurous wall of Paradise up sprung: Which to our general Sire gave prospect large Into his neather Empire neighbouring round. And higher then that Wall a circling row Of goodliest Trees loaden with fairest Fruit, Blossoms and Fruits at once of golden hue Appeerd, with gay enameld colours mixt: On which the Sun more glad impress'd his beams Then in fair Evening Cloud, or humid Bow, When God hath showrd the earth; so lovely seemd That Lantskip: And of pure now purer aire Meets his approach, and to the heart inspires Vernal delight and joy, able to drive All sadness but despair: now gentle gales Fanning thir odoriferous wings dispense Native perfumes, and whisper whence they stole Those balmie spoiles. As when to them who saile Beyond the CAPE OF HOPE, and now are past MOZAMBIC, off at Sea North-East windes blow SABEAN Odours from the spicie shoare Of ARABIE the blest, with such delay Well pleas'd they slack thir course, and many a League Cheard with the grateful smell old Ocean smiles. So entertaind those odorous sweets the Fiend Who came thir bane, though with them better pleas'd Then ASMODEUS with the fishie fume, That drove him, though enamourd, from the Spouse Of TOBITS Son, and with a vengeance sent From MEDIA post to AEGYPT, there fast bound. Now to th' ascent of that steep savage Hill SATAN had journied on, pensive and slow; But further way found none, so thick entwin'd, As one continu'd brake, the undergrowth Of shrubs and tangling bushes had perplext All path of Man or Beast that past that way: One Gate there onely was, and that look'd East On th' other side: which when th' arch-fellon saw Due entrance he disdaind, and in contempt, At one slight bound high overleap'd all bound Of Hill or highest Wall, and sheer within Lights on his feet. As when a prowling Wolfe, Whom hunger drives to seek new haunt for prey, Watching where Shepherds pen thir Flocks at eeve In hurdl'd Cotes amid the field secure, Leaps o're the fence with ease into the Fould: Or as a Thief bent to unhoord the cash Of some rich Burgher, whose substantial dores, Cross-barrd and bolted fast, fear no assault, In at the window climbes, or o're the tiles; So clomb this first grand Thief into Gods Fould: So since into his Church lewd Hirelings climbe. Thence up he flew, and on the Tree of Life, The middle Tree and highest there that grew, Sat like a Cormorant; yet not true Life Thereby regaind, but sat devising Death To them who liv'd; nor on the vertue thought Of that life-giving Plant, but only us'd For prospect, what well us'd had bin the pledge Of immortalitie. So little knows Any, but God alone, to value right The good before him, but perverts best things To worst abuse, or to thir meanest use. Beneath him with new wonder now he views To all delight of human sense expos'd In narrow room Natures whole wealth, yea more, A Heaven on Earth, for blissful Paradise Of God the Garden was, by him in the East Of EDEN planted; EDEN stretchd her Line From AURAN Eastward to the Royal Towrs Of great SELEUCIA, built by GRECIAN Kings, Or where the Sons of EDEN long before Dwelt in TELASSAR: in this pleasant soile His farr more pleasant Garden God ordaind; Out of the fertil ground he caus'd to grow All Trees of noblest kind for sight, smell, taste; And all amid them stood the Tree of Life, High eminent, blooming Ambrosial Fruit Of vegetable Gold; and next to Life Our Death the Tree of Knowledge grew fast by, Knowledge of Good bought dear by knowing ill. Southward through EDEN went a River large, Nor chang'd his course, but through the shaggie hill Pass'd underneath ingulft, for God had thrown That Mountain as his Garden mould high rais'd Upon the rapid current, which through veins Of porous Earth with kindly thirst up drawn, Rose a fresh Fountain, and with many a rill Waterd the Garden; thence united fell Down the steep glade, and met the neather Flood, Which from his darksom passage now appeers, And now divided into four main Streams, Runs divers, wandring many a famous Realme And Country whereof here needs no account, But rather to tell how, if Art could tell, How from that Saphire Fount the crisped Brooks, Rowling on Orient Pearl and sands of Gold, With mazie error under pendant shades Ran Nectar, visiting each plant, and fed Flours worthy of Paradise which not nice Art In Beds and curious Knots, but Nature boon Powrd forth profuse on Hill and Dale and Plaine, Both where the morning Sun first warmly smote The open field, and where the unpierc't shade Imbround the noontide Bowrs: Thus was this place, A happy rural seat of various view; Groves whose rich Trees wept odorous Gumms and Balme, Others whose fruit burnisht with Golden Rinde Hung amiable, HESPERIAN Fables true, If true, here onely, and of delicious taste: Betwixt them Lawns, or level Downs, and Flocks Grasing the tender herb, were interpos'd, Or palmie hilloc, or the flourie lap Of som irriguous Valley spread her store, Flours of all hue, and without Thorn the Rose: Another side, umbrageous Grots and Caves Of coole recess, o're which the mantling Vine Layes forth her purple Grape, and gently creeps Luxuriant; mean while murmuring waters fall Down the slope hills, disperst, or in a Lake, That to the fringed Bank with Myrtle crownd, Her chrystall mirror holds, unite thir streams. The Birds thir quire apply; aires, vernal aires, Breathing the smell of field and grove, attune The trembling leaves, while Universal PAN Knit with the GRACES and the HOURS in dance Led on th' Eternal Spring. Not that faire field Of ENNA, where PROSERPIN gathring flours Her self a fairer Floure by gloomie DIS Was gatherd, which cost CERES all that pain To seek her through the world; nor that sweet Grove Of DAPHNE by ORONTES, and th' inspir'd CASTALIAN Spring might with this Paradise Of EDEN strive; nor that NYSEIAN Ile Girt with the River TRITON, where old CHAM, Whom Gentiles AMMON call and LIBYAN JOVE, Hid AMALTHEA and her Florid Son Young BACCHUS from his Stepdame RHEA'S eye; Nor where ABASSIN Kings thir issue Guard, Mount AMARA, though this by som suppos'd True Paradise under the ETHIOP Line By NILUS head, enclos'd with shining Rock, A whole dayes journey high, but wide remote From this ASSYRIAN Garden, where the Fiend Saw undelighted all delight, all kind Of living Creatures new to sight and strange: Two of far nobler shape erect and tall, Godlike erect, with native Honour clad In naked Majestie seemd Lords of all, And worthie seemd, for in thir looks Divine The image of thir glorious Maker shon, Truth, Wisdome, Sanctitude severe and pure, Severe, but in true filial freedom plac't; Whence true autoritie in men; though both Not equal, as thir sex not equal seemd; For contemplation hee and valour formd, For softness shee and sweet attractive Grace, Hee for God only, shee for God in him: His fair large Front and Eye sublime declar'd Absolute rule; and Hyacinthin Locks Round from his parted forelock manly hung Clustring, but not beneath his shoulders broad: Shee as a vail down to the slender waste Her unadorned golden tresses wore Dissheveld, but in wanton ringlets wav'd As the Vine curles her tendrils, which impli'd Subjection, but requir'd with gentle sway, And by her yeilded, by him best receivd, Yeilded with coy submission, modest pride, And sweet reluctant amorous delay. Nor those mysterious parts were then conceald, Then was not guiltie shame, dishonest shame Of natures works, honor dishonorable, Sin-bred, how have ye troubl'd all mankind With shews instead, meer shews of seeming pure, And banisht from mans life his happiest life, Simplicitie and spotless innocence. So passd they naked on, nor shund the sight Of God or Angel, for they thought no ill: So hand in hand they passd, the lovliest pair That ever since in loves imbraces met, ADAM the goodliest man of men since borne His Sons, the fairest of her Daughters EVE. Under a tuft of shade that on a green Stood whispering soft, by a fresh Fountain side They sat them down, and after no more toil Of thir sweet Gardning labour then suffic'd To recommend coole ZEPHYR, and made ease More easie, wholsom thirst and appetite More grateful, to thir Supper Fruits they fell, Nectarine Fruits which the compliant boughes Yeilded them, side-long as they sat recline On the soft downie Bank damaskt with flours: The savourie pulp they chew, and in the rinde Still as they thirsted scoop the brimming stream; Nor gentle purpose, nor endearing smiles Wanted, nor youthful dalliance as beseems Fair couple, linkt in happie nuptial League, Alone as they. About them frisking playd All Beasts of th' Earth, since wilde, and of all chase In Wood or Wilderness, Forrest or Den; Sporting the Lion rampd, and in his paw Dandl'd the Kid; Bears, Tygers, Ounces, Pards Gambold before them, th' unwieldy Elephant To make them mirth us'd all his might, & wreathd His Lithe Proboscis; close the Serpent sly Insinuating, wove with Gordian twine His breaded train, and of his fatal guile Gave proof unheeded; others on the grass Coucht, and now fild with pasture gazing sat, Or Bedward ruminating: for the Sun Declin'd was hasting now with prone carreer To th' Ocean Iles, and in th' ascending Scale Of Heav'n the Starrs that usher Evening rose: When SATAN still in gaze, as first he stood, Scarce thus at length faild speech recoverd sad. O Hell! what doe mine eyes with grief behold, Into our room of bliss thus high advanc't Creatures of other mould, earth-born perhaps, Not Spirits, yet to heav'nly Spirits bright Little inferior; whom my thoughts pursue With wonder, and could love, so lively shines In them Divine resemblance, and such grace The hand that formd them on thir shape hath pourd. Ah gentle pair, yee little think how nigh Your change approaches, when all these delights Will vanish and deliver ye to woe, More woe, the more your taste is now of joy; Happie, but for so happie ill secur'd Long to continue, and this high seat your Heav'n Ill fenc't for Heav'n to keep out such a foe As now is enterd; yet no purpos'd foe To you whom I could pittie thus forlorne Though I unpittied: League with you I seek, And mutual amitie so streight, so close, That I with you must dwell, or you with me Henceforth; my dwelling haply may not please Like this fair Paradise, your sense, yet such Accept your Makers work; he gave it me, Which I as freely give; Hell shall unfould, To entertain you two, her widest Gates, And send forth all her Kings; there will be room, Not like these narrow limits, to receive Your numerous ofspring; if no better place, Thank him who puts me loath to this revenge On you who wrong me not for him who wrongd. And should I at your harmless innocence Melt, as I doe, yet public reason just, Honour and Empire with revenge enlarg'd, By conquering this new World, compels me now To do what else though damnd I should abhorre. So spake the Fiend, and with necessitie, The Tyrants plea, excus'd his devilish deeds. Then from his loftie stand on that high Tree Down he alights among the sportful Herd Of those fourfooted kindes, himself now one, Now other, as thir shape servd best his end Neerer to view his prey, and unespi'd To mark what of thir state he more might learn By word or action markt: about them round A Lion now he stalkes with fierie glare, Then as a Tiger, who by chance hath spi'd In some Purlieu two gentle Fawnes at play, Strait couches close, then rising changes oft His couchant watch, as one who chose his ground Whence rushing he might surest seise them both Grip't in each paw: when ADAM first of men To first of women EVE thus moving speech, Turnd him all eare to heare new utterance flow. Sole partner and sole part of all these joyes, Dearer thy self then all; needs must the Power That made us, and for us this ample World Be infinitly good, and of his good As liberal and free as infinite, That rais'd us from the dust and plac't us here In all this happiness, who at his hand Have nothing merited, nor can performe Aught whereof hee hath need, hee who requires From us no other service then to keep This one, this easie charge, of all the Trees In Paradise that beare delicious fruit So various, not to taste that onely Tree Of knowledge, planted by the Tree of Life, So neer grows Death to Life, what ere Death is, Som dreadful thing no doubt; for well thou knowst God hath pronounc't it death to taste that Tree, The only sign of our obedience left Among so many signes of power and rule Conferrd upon us, and Dominion giv'n Over all other Creatures that possesse Earth, Aire, and Sea. Then let us not think hard One easie prohibition, who enjoy Free leave so large to all things else, and choice Unlimited of manifold delights: But let us ever praise him, and extoll His bountie, following our delightful task To prune these growing Plants, & tend these Flours, Which were it toilsom, yet with thee were sweet. To whom thus Eve repli'd. O thou for whom And from whom I was formd flesh of thy flesh, And without whom am to no end, my Guide And Head, what thou hast said is just and right. For wee to him indeed all praises owe, And daily thanks, I chiefly who enjoy So farr the happier Lot, enjoying thee Preeminent by so much odds, while thou Like consort to thy self canst no where find. That day I oft remember, when from sleep I first awak't, and found my self repos'd Under a shade on flours, much wondring where And what I was, whence thither brought, and how. Not distant far from thence a murmuring sound Of waters issu'd from a Cave and spread Into a liquid Plain, then stood unmov'd Pure as th' expanse of Heav'n; I thither went With unexperienc't thought, and laid me downe On the green bank, to look into the cleer Smooth Lake, that to me seemd another Skie. As I bent down to look, just opposite, A Shape within the watry gleam appeerd Bending to look on me, I started back, It started back, but pleasd I soon returnd, Pleas'd it returnd as soon with answering looks Of sympathie and love, there I had fixt Mine eyes till now, and pin'd with vain desire, Had not a voice thus warnd me, What thou seest, What there thou seest fair Creature is thy self, With thee it came and goes: but follow me, And I will bring thee where no shadow staies Thy coming, and thy soft imbraces, hee Whose image thou art, him thou shall enjoy Inseparablie thine, to him shalt beare Multitudes like thy self, and thence be call'd Mother of human Race: what could I doe, But follow strait, invisibly thus led? Till I espi'd thee, fair indeed and tall, Under a Platan, yet methought less faire, Less winning soft, less amiablie milde, Then that smooth watry image; back I turnd, Thou following cryd'st aloud, Return fair EVE, Whom fli'st thou? whom thou fli'st, of him thou art, His flesh, his bone; to give thee being I lent Out of my side to thee, neerest my heart Substantial Life, to have thee by my side Henceforth an individual solace dear; Part of my Soul I seek thee, and thee claim My other half: with that thy gentle hand Seisd mine, I yeilded, and from that time see How beauty is excelld by manly grace And wisdom, which alone is truly fair. So spake our general Mother, and with eyes Of conjugal attraction unreprov'd, And meek surrender, half imbracing leand On our first Father, half her swelling Breast Naked met his under the flowing Gold Of her loose tresses hid: he in delight Both of her Beauty and submissive Charms Smil'd with superior Love, as JUPITER On JUNO smiles, when he impregns the Clouds That shed MAY Flowers; and press'd her Matron lip With kisses pure: aside the Devil turnd For envie, yet with jealous leer maligne Ey'd them askance, and to himself thus plaind. Sight hateful, sight tormenting! thus these two Imparadis't in one anothers arms The happier EDEN, shall enjoy thir fill Of bliss on bliss, while I to Hell am thrust, Where neither joy nor love, but fierce desire, Among our other torments not the least, Still unfulfill'd with pain of longing pines; Yet let me not forget what I have gain'd From thir own mouths; all is not theirs it seems: One fatal Tree there stands of Knowledge call'd, Forbidden them to taste: Knowledge forbidd'n? Suspicious, reasonless. Why should thir Lord Envie them that? can it be sin to know, Can it be death? and do they onely stand By Ignorance, is that thir happie state, The proof of thir obedience and thir faith? O fair foundation laid whereon to build Thir ruine! Hence I will excite thir minds With more desire to know, and to reject Envious commands, invented with designe To keep them low whom knowledge might exalt Equal with Gods; aspiring to be such, They taste and die: what likelier can ensue? But first with narrow search I must walk round This Garden, and no corner leave unspi'd; A chance but chance may lead where I may meet Some wandring Spirit of Heav'n, by Fountain side, Or in thick shade retir'd, from him to draw What further would be learnt. Live while ye may, Yet happie pair; enjoy, till I return, Short pleasures, for long woes are to succeed. So saying, his proud step he scornful turn'd, But with sly circumspection, and began Through wood, through waste, o're hil, o're dale his roam. Mean while in utmost Longitude, where Heav'n With Earth and Ocean meets, the setting Sun Slowly descended, and with right aspect Against the eastern Gate of Paradise Leveld his eevning Rayes: it was a Rock Of Alablaster, pil'd up to the Clouds, Conspicuous farr, winding with one ascent Accessible from Earth, one entrance high; The rest was craggie cliff, that overhung Still as it rose, impossible to climbe. Betwixt these rockie Pillars GABRIEL sat Chief of th' Angelic Guards, awaiting night; About him exercis'd Heroic Games Th' unarmed Youth of Heav'n, but nigh at hand Celestial Armourie, Shields, Helmes, and Speares Hung high with Diamond flaming, and with Gold. Thither came URIEL, gliding through the Eeven On a Sun beam, swift as a shooting Starr In AUTUMN thwarts the night, when vapors fir'd Impress the Air, and shews the Mariner From what point of his Compass to beware Impetuous winds: he thus began in haste. GABRIEL, to thee thy cours by Lot hath giv'n Charge and strict watch that to this happie place No evil thing approach or enter in; This day at highth of Noon came to my Spheare A Spirit, zealous, as he seem'd, to know More of th' Almighties works, and chiefly Man Gods latest Image: I describ'd his way Bent all on speed, and markt his Aerie Gate; But in the Mount that lies from EDEN North, Where he first lighted, soon discernd his looks Alien from Heav'n, with passions foul obscur'd: Mine eye pursu'd him still, but under shade Lost sight of him; one of the banisht crew I fear, hath ventur'd from the deep, to raise New troubles; him thy care must be to find. To whom the winged Warriour thus returnd: URIEL, no wonder if thy perfet sight, Amid the Suns bright circle where thou sitst, See farr and wide: in at this Gate none pass The vigilance here plac't, but such as come Well known from Heav'n; and since Meridian hour No Creature thence: if Spirit of other sort, So minded, have oreleapt these earthie bounds On purpose, hard thou knowst it to exclude Spiritual substance with corporeal barr. But if within the circuit of these walks In whatsoever shape he lurk, of whom Thou telst, by morrow dawning I shall know. So promis'd hee, and URIEL to his charge Returnd on that bright beam, whose point now raisd Bore him slope downward to the Sun now fall'n Beneath th' AZORES; whither the prime Orb, Incredible how swift, had thither rowl'd Diurnal, or this less volubil Earth By shorter flight to th' East, had left him there Arraying with reflected Purple and Gold The Clouds that on his Western Throne attend: Now came still Eevning on, and Twilight gray Had in her sober Liverie all things clad; Silence accompanied, for Beast and Bird, They to thir grassie Couch, these to thir Nests Were slunk, all but the wakeful Nightingale; She all night long her amorous descant sung; Silence was pleas'd: now glow'd the Firmament With living Saphirs: HESPERUS that led The starrie Host, rode brightest, till the Moon Rising in clouded Majestie, at length Apparent Queen unvaild her peerless light, And o're the dark her Silver Mantle threw. When ADAM thus to EVE: Fair Consort, th' hour Of night, and all things now retir'd to rest Mind us of like repose, since God hath set Labour and rest, as day and night to men Successive, and the timely dew of sleep Now falling with soft slumbrous weight inclines Our eye-lids; other Creatures all day long Rove idle unimploid, and less need rest; Man hath his daily work of body or mind Appointed, which declares his Dignitie, And the regard of Heav'n on all his waies; While other Animals unactive range, And of thir doings God takes no account. Tomorrow ere fresh Morning streak the East With first approach of light, we must be ris'n, And at our pleasant labour, to reform Yon flourie Arbors, yonder Allies green, Our walks at noon, with branches overgrown, That mock our scant manuring, and require More hands then ours to lop thir wanton growth: Those Blossoms also, and those dropping Gumms, That lie bestrowne unsightly and unsmooth, Ask riddance, if we mean to tread with ease; Mean while, as Nature wills, Night bids us rest. To whom thus EVE with perfet beauty adornd. My Author and Disposer, what thou bidst Unargu'd I obey; so God ordains, God is thy Law, thou mine: to know no more Is womans happiest knowledge and her praise. With thee conversing I forget all time, All seasons and thir change, all please alike. Sweet is the breath of morn, her rising sweet, With charm of earliest Birds; pleasant the Sun When first on this delightful Land he spreads His orient Beams, on herb, tree, fruit, and flour, Glistring with dew; fragrant the fertil earth After soft showers; and sweet the coming on Of grateful Eevning milde, then silent Night With this her solemn Bird and this fair Moon, And these the Gemms of Heav'n, her starrie train: But neither breath of Morn when she ascends With charm of earliest Birds, nor rising Sun On this delightful land, nor herb, fruit, floure, Glistring with dew, nor fragrance after showers, Nor grateful Evening mild, nor silent Night With this her solemn Bird, nor walk by Moon, Or glittering Starr-light without thee is sweet. But wherfore all night long shine these, for whom This glorious sight, when sleep hath shut all eyes? To whom our general Ancestor repli'd. Daughter of God and Man, accomplisht EVE, Those have thir course to finish, round the Earth, By morrow Eevning, and from Land to Land In order, though to Nations yet unborn, Ministring light prepar'd, they set and rise; Least total darkness should by Night regaine Her old possession, and extinguish life In Nature and all things, which these soft fires Not only enlighten, but with kindly heate Of various influence foment and warme, Temper or nourish, or in part shed down Thir stellar vertue on all kinds that grow On Earth, made hereby apter to receive Perfection from the Suns more potent Ray. These then, though unbeheld in deep of night, Shine not in vain, nor think, though men were none, That heav'n would want spectators, God want praise; Millions of spiritual Creatures walk the Earth Unseen, both when we wake, and when we sleep: All these with ceasless praise his works behold Both day and night: how often from the steep Of echoing Hill or Thicket have we heard Celestial voices to the midnight air, Sole, or responsive each to others note Singing thir great Creator: oft in bands While they keep watch, or nightly rounding walk With Heav'nly touch of instrumental sounds In full harmonic number joind, thir songs Divide the night, and lift our thoughts to Heaven. Thus talking hand in hand alone they pass'd On to thir blissful Bower; it was a place Chos'n by the sovran Planter, when he fram'd All things to mans delightful use; the roofe Of thickest covert was inwoven shade Laurel and Mirtle, and what higher grew Of firm and fragrant leaf; on either side ACANTHUS, and each odorous bushie shrub Fenc'd up the verdant wall; each beauteous flour, IRIS all hues, Roses, and Gessamin Rear'd high thir flourisht heads between, and wrought Mosaic; underfoot the Violet, Crocus, and Hyacinth with rich inlay Broiderd the ground, more colour'd then with stone Of costliest Emblem: other Creature here Beast, Bird, Insect, or Worm durst enter none; Such was thir awe of man. In shadier Bower More sacred and sequesterd, though but feignd, PAN or SILVANUS never slept, nor Nymph, Nor FAUNUS haunted. Here in close recess With Flowers, Garlands, and sweet-smelling Herbs Espoused EVE deckt first her Nuptial Bed, And heav'nly Quires the Hymenaean sung, What day the genial Angel to our Sire Brought her in naked beauty more adorn'd, More lovely then PANDORA, whom the Gods Endowd with all thir gifts, and O too like In sad event, when to the unwiser Son Of JAPHET brought by HERMES, she ensnar'd Mankind with her faire looks, to be aveng'd On him who had stole JOVES authentic fire. Thus at thir shadie Lodge arriv'd, both stood, Both turnd, and under op'n Skie ador'd The God that made both Skie, Air, Earth & Heav'n Which they beheld, the Moons resplendent Globe And starrie Pole: Thou also mad'st the Night, Maker Omnipotent, and thou the Day, Which we in our appointed work imployd Have finisht happie in our mutual help And mutual love, the Crown of all our bliss Ordain'd by thee, and this delicious place For us too large, where thy abundance wants Partakers, and uncropt falls to the ground. But thou hast promis'd from us two a Race To fill the Earth, who shall with us extoll Thy goodness infinite, both when we wake, And when we seek, as now, thy gift of sleep. This said unanimous, and other Rites Observing none, but adoration pure Which God likes best, into thir inmost bower Handed they went; and eas'd the putting off These troublesom disguises which wee wear, Strait side by side were laid, nor turnd I weene ADAM from his fair Spouse, nor EVE the Rites Mysterious of connubial Love refus'd: Whatever Hypocrites austerely talk Of puritie and place and innocence, Defaming as impure what God declares Pure, and commands to som, leaves free to all. Our Maker bids increase, who bids abstain But our Destroyer, foe to God and Man? Haile wedded Love, mysterious Law, true source Of human ofspring, sole proprietie, In Paradise of all things common else. By thee adulterous lust was driv'n from men Among the bestial herds to raunge, by thee Founded in Reason, Loyal, Just, and Pure, Relations dear, and all the Charities Of Father, Son, and Brother first were known. Farr be it, that I should write thee sin or blame, Or think thee unbefitting holiest place, Perpetual Fountain of Domestic sweets, Whose Bed is undefil'd and chast pronounc't, Present, or past, as Saints and Patriarchs us'd. Here Love his golden shafts imploies, here lights His constant Lamp, and waves his purple wings, Reigns here and revels; not in the bought smile Of Harlots, loveless, joyless, unindeard, Casual fruition, nor in Court Amours Mixt Dance, or wanton Mask, or Midnight Bal, Or Serenate, which the starv'd Lover sings To his proud fair, best quitted with disdain. These lulld by Nightingales imbraceing slept, And on thir naked limbs the flourie roof Showrd Roses, which the Morn repair'd. Sleep on, Blest pair; and O yet happiest if ye seek No happier state, and know to know no more. Now had night measur'd with her shaddowie Cone Half way up Hill this vast Sublunar Vault, And from thir Ivorie Port the Cherubim Forth issuing at th' accustomd hour stood armd To thir night watches in warlike Parade, When GABRIEL to his next in power thus spake. UZZIEL, half these draw off, and coast the South With strictest watch; these other wheel the North, Our circuit meets full West. As flame they part Half wheeling to the Shield, half to the Spear. From these, two strong and suttle Spirits he calld That neer him stood, and gave them thus in charge. ITHURIEL and ZEPHON, with wingd speed Search through this Garden, leav unsearcht no nook, But chiefly where those two fair Creatures Lodge, Now laid perhaps asleep secure of harme. This Eevning from the Sun's decline arriv'd Who tells of som infernal Spirit seen Hitherward bent (who could have thought?) escap'd The barrs of Hell, on errand bad no doubt: Such where ye find, seise fast, and hither bring. So saying, on he led his radiant Files, Daz'ling the Moon; these to the Bower direct In search of whom they sought: him there they found Squat like a Toad, close at the eare of EVE; Assaying by his Devilish art to reach The Organs of her Fancie, and with them forge Illusions as he list, Phantasms and Dreams, Or if, inspiring venom, he might taint Th' animal Spirits that from pure blood arise Like gentle breaths from Rivers pure, thence raise At least distemperd, discontented thoughts, Vain hopes, vain aimes, inordinate desires Blown up with high conceits ingendring pride. Him thus intent ITHURIEL with his Spear Touch'd lightly; for no falshood can endure Touch of Celestial temper, but returns Of force to its own likeness: up he starts Discoverd and surpriz'd. As when a spark Lights on a heap of nitrous Powder, laid Fit for the Tun som Magazin to store Against a rumord Warr, the Smuttie graine With sudden blaze diffus'd, inflames the Aire: So started up in his own shape the Fiend. Back stept those two fair Angels half amaz'd So sudden to behold the grieslie King; Yet thus, unmovd with fear, accost him soon. Which of those rebell Spirits adjudg'd to Hell Com'st thou, escap'd thy prison, and transform'd, Why satst thou like an enemie in waite Here watching at the head of these that sleep? Know ye not then said SATAN, filld with scorn, Know ye not me? ye knew me once no mate For you, there sitting where ye durst not soare; Not to know mee argues your selves unknown, The lowest of your throng; or if ye know, Why ask ye, and superfluous begin Your message, like to end as much in vain? To whom thus ZEPHON, answering scorn with scorn. Think not, revolted Spirit, thy shape the same, Or undiminisht brightness, to be known As when thou stoodst in Heav'n upright and pure; That Glorie then, when thou no more wast good, Departed from thee, and thou resembl'st now Thy sin and place of doom obscure and foule. But come, for thou, be sure, shalt give account To him who sent us, whose charge is to keep This place inviolable, and these from harm. So spake the Cherube, and his grave rebuke Severe in youthful beautie, added grace Invincible: abasht the Devil stood, And felt how awful goodness is, and saw Vertue in her shape how lovly, saw, and pin'd His loss; but chiefly to find here observd His lustre visibly impar'd; yet seemd Undaunted. If I must contend, said he, Best with the best, the Sender not the sent, Or all at once; more glorie will be wonn, Or less be lost. Thy fear, said ZEPHON bold, Will save us trial what the least can doe Single against thee wicked, and thence weak. The Fiend repli'd not, overcome with rage; But like a proud Steed reind, went hautie on, Chaumping his iron curb: to strive or flie He held it vain; awe from above had quelld His heart, not else dismai'd. Now drew they nigh The western point, where those half-rounding guards Just met, & closing stood in squadron joind Awaiting next command. To whom thir Chief GABRIEL from the Front thus calld aloud. O friends, I hear the tread of nimble feet Hasting this way, and now by glimps discerne ITHURIEL and ZEPHON through the shade, And with them comes a third of Regal port, But faded splendor wan; who by his gate And fierce demeanour seems the Prince of Hell, Not likely to part hence without contest; Stand firm, for in his look defiance lours. He scarce had ended, when those two approachd And brief related whom they brought, wher found, How busied, in what form and posture coucht. To whom with stern regard thus GABRIEL spake. Why hast thou, SATAN, broke the bounds prescrib'd To thy transgressions, and disturbd the charge Of others, who approve not to transgress By thy example, but have power and right To question thy bold entrance on this place; Imploi'd it seems to violate sleep, and those Whose dwelling God hath planted here in bliss? To whom thus SATAN with contemptuous brow. GABRIEL, thou hadst in Heav'n th' esteem of wise, And such I held thee; but this question askt Puts me in doubt. Lives ther who loves his pain? Who would not, finding way, break loose from Hell, Though thither doomd? Thou wouldst thy self, no doubt, And boldly venture to whatever place Farthest from pain, where thou mightst hope to change Torment with ease, & soonest recompence Dole with delight, which in this place I sought; To thee no reason; who knowst only good, But evil hast not tri'd: and wilt object His will who bound us? let him surer barr His Iron Gates, if he intends our stay In that dark durance: thus much what was askt. The rest is true, they found me where they say; But that implies not violence or harme. Thus hee in scorn. The warlike Angel mov'd, Disdainfully half smiling thus repli'd. O loss of one in Heav'n to judge of wise, Since SATAN fell, whom follie overthrew, And now returns him from his prison scap't, Gravely in doubt whether to hold them wise Or not, who ask what boldness brought him hither Unlicenc't from his bounds in Hell prescrib'd; So wise he judges it to fly from pain However, and to scape his punishment. So judge thou still, presumptuous, till the wrauth, Which thou incurr'st by flying, meet thy flight Seavenfold, and scourge that wisdom back to Hell, Which taught thee yet no better, that no pain Can equal anger infinite provok't. But wherefore thou alone? wherefore with thee Came not all Hell broke loose? is pain to them Less pain, less to be fled, or thou then they Less hardie to endure? courageous Chief, The first in flight from pain, had'st thou alleg'd To thy deserted host this cause of flight, Thou surely hadst not come sole fugitive. To which the Fiend thus answerd frowning stern. Not that I less endure, or shrink from pain, Insulting Angel, well thou knowst I stood Thy fiercest, when in Battel to thy aide The blasting volied Thunder made all speed And seconded thy else not dreaded Spear. But still thy words at random, as before, Argue thy inexperience what behooves From hard assaies and ill successes past A faithful Leader, not to hazard all Through wayes of danger by himself untri'd. I therefore, I alone first undertook To wing the desolate Abyss, and spie This new created World, whereof in Hell Fame is not silent, here in hope to find Better abode, and my afflicted Powers To settle here on Earth, or in mid Aire; Though for possession put to try once more What thou and thy gay Legions dare against; Whose easier business were to serve thir Lord High up in Heav'n, with songs to hymne his Throne, And practis'd distances to cringe, not fight. To whom the warriour Angel soon repli'd. To say and strait unsay, pretending first Wise to flie pain, professing next the Spie, Argues no Leader, but a lyar trac't, SATAN, and couldst thou faithful add? O name, O sacred name of faithfulness profan'd! Faithful to whom? to thy rebellious crew? Armie of Fiends, fit body to fit head; Was this your discipline and faith ingag'd, Your military obedience, to dissolve Allegeance to th' acknowledg'd Power supream? And thou sly hypocrite, who now wouldst seem Patron of liberty, who more then thou Once fawn'd, and cring'd, and servilly ador'd Heav'ns awful Monarch? wherefore but in hope To dispossess him, and thy self to reigne? But mark what I arreede thee now, avant; Flie thither whence thou fledst: if from this houre Within these hallowd limits thou appeer, Back to th' infernal pit I drag thee chaind, And Seale thee so, as henceforth not to scorne The facil gates of hell too slightly barrd. So threatn'd hee, but SATAN to no threats Gave heed, but waxing more in rage repli'd. Then when I am thy captive talk of chaines, Proud limitarie Cherube, but ere then Farr heavier load thy self expect to feel From my prevailing arme, though Heavens King Ride on thy wings, and thou with thy Compeers, Us'd to the yoak, draw'st his triumphant wheels In progress through the rode of Heav'n Star-pav'd. While thus he spake, th' Angelic Squadron bright Turnd fierie red, sharpning in mooned hornes Thir Phalanx, and began to hemm him round With ported Spears, as thick as when a field Of CERES ripe for harvest waving bends Her bearded Grove of ears, which way the wind Swayes them; the careful Plowman doubting stands Least on the threshing floore his hopeful sheaves Prove chaff. On th' other side SATAN allarm'd Collecting all his might dilated stood, Like TENERIFF or ATLAS unremov'd: His stature reacht the Skie, and on his Crest Sat horror Plum'd; nor wanted in his graspe What seemd both Spear and Shield: now dreadful deeds Might have ensu'd, nor onely Paradise In this commotion, but the Starrie Cope Of Heav'n perhaps, or all the Elements At least had gon to rack, disturbd and torne With violence of this conflict, had not soon Th' Eternal to prevent such horrid fray Hung forth in Heav'n his golden Scales, yet seen Betwixt ASTREA and the SCORPION signe, Wherein all things created first he weighd, The pendulous round Earth with ballanc't Aire In counterpoise, now ponders all events, Battels and Realms: in these he put two weights The sequel each of parting and of fight; The latter quick up flew, and kickt the beam; Which GABRIEL spying, thus bespake the Fiend. SATAN, I know thy strength, and thou knowst mine, Neither our own but giv'n; what follie then To boast what Arms can doe, since thine no more Then Heav'n permits, nor mine, though doubld now To trample thee as mire: for proof look up, And read thy Lot in yon celestial Sign Where thou art weigh'd, & shown how light, how weak, If thou resist. The Fiend lookt up and knew His mounted scale aloft: nor more; but fled Murmuring, and with him fled the shades of night. THE END OF THE FOURTH BOOK. PARADISE LOST BOOK V. Now Morn her rosie steps in th' Eastern Clime Advancing, sow'd the Earth with Orient Pearle, When ADAM wak't, so customd, for his sleep Was Aerie light, from pure digestion bred, And temperat vapors bland, which th' only sound Of leaves and fuming rills, AURORA's fan, Lightly dispers'd, and the shrill Matin Song Of Birds on every bough; so much the more His wonder was to find unwak'nd EVE With Tresses discompos'd, and glowing Cheek, As through unquiet rest: he on his side Leaning half-rais'd, with looks of cordial Love Hung over her enamour'd, and beheld Beautie, which whether waking or asleep, Shot forth peculiar Graces; then with voice Milde, as when ZEPHYRUS on FLORA breathes, Her hand soft touching, whisperd thus. Awake My fairest, my espous'd, my latest found, Heav'ns last best gift, my ever new delight, Awake, the morning shines, and the fresh field Calls us, we lose the prime, to mark how spring Our tended Plants, how blows the Citron Grove, What drops the Myrrhe, & what the balmie Reed, How Nature paints her colours, how the Bee Sits on the Bloom extracting liquid sweet. Such whispering wak'd her, but with startl'd eye On ADAM, whom imbracing, thus she spake. O Sole in whom my thoughts find all repose, My Glorie, my Perfection, glad I see Thy face, and Morn return'd, for I this Night, Such night till this I never pass'd, have dream'd, If dream'd, not as I oft am wont, of thee, Works of day pass't, or morrows next designe, But of offence and trouble, which my mind Knew never till this irksom night; methought Close at mine ear one call'd me forth to walk With gentle voice, I thought it thine; it said, Why sleepst thou EVE? now is the pleasant time, The cool, the silent, save where silence yields To the night-warbling Bird, that now awake Tunes sweetest his love-labor'd song; now reignes Full Orb'd the Moon, and with more pleasing light Shadowie sets off the face of things; in vain, If none regard; Heav'n wakes with all his eyes, Whom to behold but thee, Natures desire, In whose sight all things joy, with ravishment Attracted by thy beauty still to gaze. I rose as at thy call, but found thee not; To find thee I directed then my walk; And on, methought, alone I pass'd through ways That brought me on a sudden to the Tree Of interdicted Knowledge: fair it seem'd, Much fairer to my Fancie then by day: And as I wondring lookt, beside it stood One shap'd & wing'd like one of those from Heav'n By us oft seen; his dewie locks distill'd Ambrosia; on that Tree he also gaz'd; And O fair Plant, said he, with fruit surcharg'd, Deigns none to ease thy load and taste thy sweet, Nor God, nor Man; is Knowledge so despis'd? Or envie, or what reserve forbids to taste? Forbid who will, none shall from me withhold Longer thy offerd good, why else set here? This said he paus'd not, but with ventrous Arme He pluckt, he tasted; mee damp horror chil'd At such bold words voucht with a deed so bold: But he thus overjoy'd, O Fruit Divine, Sweet of thy self, but much more sweet thus cropt, Forbidd'n here, it seems, as onely fit For Gods, yet able to make Gods of Men: And why not Gods of Men, since good, the more Communicated, more abundant growes, The Author not impair'd, but honourd more? Here, happie Creature, fair Angelic EVE, Partake thou also; happie though thou art, Happier thou mayst be, worthier canst not be: Taste this, and be henceforth among the Gods Thy self a Goddess, not to Earth confind, But somtimes in the Air, as wee, somtimes Ascend to Heav'n, by merit thine, and see What life the Gods live there, and such live thou. So saying, he drew nigh, and to me held, Even to my mouth of that same fruit held part Which he had pluckt; the pleasant savourie smell So quick'nd appetite, that I, methought, Could not but taste. Forthwith up to the Clouds With him I flew, and underneath beheld The Earth outstretcht immense, a prospect wide And various: wondring at my flight and change To this high exaltation; suddenly My Guide was gon, and I, me thought, sunk down, And fell asleep; but O how glad I wak'd To find this but a dream! Thus EVE her Night Related, and thus ADAM answerd sad. Best Image of my self and dearer half, The trouble of thy thoughts this night in sleep Affects me equally; nor can I like This uncouth dream, of evil sprung I fear; Yet evil whence? in thee can harbour none, Created pure. But know that in the Soule Are many lesser Faculties that serve Reason as chief; among these Fansie next Her office holds; of all external things, Which the five watchful Senses represent, She forms Imaginations, Aerie shapes, Which Reason joyning or disjoyning, frames All what we affirm or what deny, and call Our knowledge or opinion; then retires Into her private Cell when Nature rests. Oft in her absence mimic Fansie wakes To imitate her; but misjoyning shapes, Wilde work produces oft, and most in dreams, Ill matching words and deeds long past or late. Som such resemblances methinks I find Of our last Eevnings talk, in this thy dream, But with addition strange; yet be not sad. Evil into the mind of God or Man May come and go, so unapprov'd, and leave No spot or blame behind: Which gives me hope That what in sleep thou didst abhorr to dream, Waking thou never wilt consent to do. Be not disheart'nd then, nor cloud those looks That wont to be more chearful and serene Then when fair Morning first smiles on the World, And let us to our fresh imployments rise Among the Groves, the Fountains, and the Flours That open now thir choicest bosom'd smells Reservd from night, and kept for thee in store. So cheard he his fair Spouse, and she was cheard, But silently a gentle tear let fall From either eye, and wip'd them with her haire; Two other precious drops that ready stood, Each in thir chrystal sluce, hee ere they fell Kiss'd as the gracious signs of sweet remorse And pious awe, that feard to have offended. So all was cleard, and to the Field they haste. But first from under shadie arborous roof, Soon as they forth were come to open sight Of day-spring, and the Sun, who scarce up risen With wheels yet hov'ring o're the Ocean brim, Shot paralel to the earth his dewie ray, Discovering in wide Lantskip all the East Of Paradise and EDENS happie Plains, Lowly they bow'd adoring, and began Thir Orisons, each Morning duly paid In various style, for neither various style Nor holy rapture wanted they to praise Thir Maker, in fit strains pronounc't or sung Unmeditated, such prompt eloquence Flowd from thir lips, in Prose or numerous Verse, More tuneable then needed Lute or Harp To add more sweetness, and they thus began. These are thy glorious works, Parent of good, Almightie, thine this universal Frame, Thus wondrous fair; thy self how wondrous then! Unspeakable, who sitst above these Heavens To us invisible or dimly seen In these thy lowest works, yet these declare Thy goodness beyond thought, and Power Divine: Speak yee who best can tell, ye Sons of light, Angels, for yee behold him, and with songs And choral symphonies, Day without Night, Circle his Throne rejoycing, yee in Heav'n, On Earth joyn all yee Creatures to extoll Him first, him last, him midst, and without end. Fairest of Starrs, last in the train of Night, If better thou belong not to the dawn, Sure pledge of day, that crownst the smiling Morn With thy bright Circlet, praise him in thy Spheare While day arises, that sweet hour of Prime. Thou Sun, of this great World both Eye and Soule, Acknowledge him thy Greater, sound his praise In thy eternal course, both when thou climb'st, And when high Noon hast gaind, & when thou fallst. Moon, that now meetst the orient Sun, now fli'st With the fixt Starrs, fixt in thir Orb that flies, And yee five other wandring Fires that move In mystic Dance not without Song, resound His praise, who out of Darkness call'd up Light. Aire, and ye Elements the eldest birth Of Natures Womb, that in quaternion run Perpetual Circle, multiform; and mix And nourish all things, let your ceasless change Varie to our great Maker still new praise. Ye Mists and Exhalations that now rise From Hill or steaming Lake, duskie or grey, Till the Sun paint your fleecie skirts with Gold, In honour to the Worlds great Author rise, Whether to deck with Clouds the uncolourd skie, Or wet the thirstie Earth with falling showers, Rising or falling still advance his praise. His praise ye Winds, that from four Quarters blow, Breath soft or loud; and wave your tops, ye Pines, With every Plant, in sign of Worship wave. Fountains and yee, that warble, as ye flow, Melodious murmurs, warbling tune his praise. Joyn voices all ye living Souls, ye Birds, That singing up to Heaven Gate ascend, Bear on your wings and in your notes his praise; Yee that in Waters glide, and yee that walk The Earth, and stately tread, or lowly creep; Witness if I be silent, Morn or Eeven, To Hill, or Valley, Fountain, or fresh shade Made vocal by my Song, and taught his praise. Hail universal Lord, be bounteous still To give us onely good; and if the night Have gathered aught of evil or conceald, Disperse it, as now light dispels the dark. So pray'd they innocent, and to thir thoughts Firm peace recoverd soon and wonted calm. On to thir mornings rural work they haste Among sweet dewes and flours; where any row Of Fruit-trees overwoodie reachd too farr Thir pamperd boughes, and needed hands to check Fruitless imbraces: or they led the Vine To wed her Elm; she spous'd about him twines Her mariageable arms, and with her brings Her dowr th' adopted Clusters, to adorn His barren leaves. Them thus imploid beheld With pittie Heav'ns high King, and to him call'd RAPHAEL, the sociable Spirit, that deign'd To travel with TOBIAS, and secur'd His marriage with the seaventimes-wedded Maid. RAPHAEL, said hee, thou hear'st what stir on Earth SATAN from Hell scap't through the darksom Gulf Hath raisd in Paradise, and how disturbd This night the human pair, how he designes In them at once to ruin all mankind. Go therefore, half this day as friend with friend Converse with ADAM, in what Bowre or shade Thou find'st him from the heat of Noon retir'd, To respit his day-labour with repast, Or with repose; and such discourse bring on, As may advise him of his happie state, Happiness in his power left free to will, Left to his own free Will, his Will though free, Yet mutable; whence warne him to beware He swerve not too secure: tell him withall His danger, and from whom, what enemie Late falln himself from Heav'n, is plotting now The fall of others from like state of bliss; By violence, no, for that shall be withstood, But by deceit and lies; this let him know, Least wilfully transgressing he pretend Surprisal, unadmonisht, unforewarnd. So spake th' Eternal Father, and fulfilld All Justice: nor delaid the winged Saint After his charge receivd, but from among Thousand Celestial Ardors, where he stood Vaild with his gorgeous wings, up springing light Flew through the midst of Heav'n; th' angelic Quires On each hand parting, to his speed gave way Through all th' Empyreal road; till at the Gate Of Heav'n arriv'd, the gate self-opend wide On golden Hinges turning, as by work Divine the sov'ran Architect had fram'd. From hence, no cloud, or, to obstruct his sight, Starr interpos'd, however small he sees, Not unconform to other shining Globes, Earth and the Gard'n of God, with Cedars crownd Above all Hills. As when by night the Glass Of GALILEO, less assur'd, observes Imagind Lands and Regions in the Moon: Or Pilot from amidst the CYCLADES DELOS or SAMOS first appeering kenns A cloudy spot. Down thither prone in flight He speeds, and through the vast Ethereal Skie Sailes between worlds & worlds, with steddie wing Now on the polar windes, then with quick Fann Winnows the buxom Air; till within soare Of Towring Eagles, to all the Fowles he seems A PHOENIX, gaz'd by all, as that sole Bird When to enshrine his reliques in the Sun's Bright Temple, to AEGYPTIAN THEB'S he flies. At once on th' Eastern cliff of Paradise He lights, and to his proper shape returns A Seraph wingd; six wings he wore, to shade His lineaments Divine; the pair that clad Each shoulder broad, came mantling o're his brest With regal Ornament; the middle pair Girt like a Starrie Zone his waste, and round Skirted his loines and thighes with downie Gold And colours dipt in Heav'n; the third his feet Shaddowd from either heele with featherd maile Skie-tinctur'd grain. Like MAIA'S son he stood, And shook his Plumes, that Heav'nly fragrance filld The circuit wide. Strait knew him all the bands Of Angels under watch; and to his state, And to his message high in honour rise; For on som message high they guessd him bound. Thir glittering Tents he passd, and now is come Into the blissful field, through Groves of Myrrhe, And flouring Odours, Cassia, Nard, and Balme; A Wilderness of sweets; for Nature here Wantond as in her prime, and plaid at will Her Virgin Fancies, pouring forth more sweet, Wilde above rule or art; enormous bliss. Him through the spicie Forrest onward com ADAM discernd, as in the dore he sat Of his coole Bowre, while now the mounted Sun Shot down direct his fervid Raies, to warme Earths inmost womb, more warmth then ADAM need; And EVE within, due at her hour prepar'd For dinner savourie fruits, of taste to please True appetite, and not disrelish thirst Of nectarous draughts between, from milkie stream, Berrie or Grape: to whom thus ADAM call'd. Haste hither EVE, and worth thy sight behold Eastward among those Trees, what glorious shape Comes this way moving; seems another Morn Ris'n on mid-noon; som great behest from Heav'n To us perhaps he brings, and will voutsafe This day to be our Guest. But goe with speed, And what thy stores contain, bring forth and poure Abundance, fit to honour and receive Our Heav'nly stranger; well we may afford Our givers thir own gifts, and large bestow From large bestowd, where Nature multiplies Her fertil growth, and by disburd'ning grows More fruitful, which instructs us not to spare. To whom thus EVE. ADAM, earths hallowd mould, Of God inspir'd, small store will serve, where store, All seasons, ripe for use hangs on the stalk; Save what by frugal storing firmness gains To nourish, and superfluous moist consumes: But I will haste and from each bough and break, Each Plant & juciest Gourd will pluck such choice To entertain our Angel guest, as hee Beholding shall confess that here on Earth God hath dispenst his bounties as in Heav'n. So saying, with dispatchful looks in haste She turns, on hospitable thoughts intent What choice to chuse for delicacie best, What order, so contriv'd as not to mix Tastes, not well joynd, inelegant, but bring Taste after taste upheld with kindliest change, Bestirs her then, and from each tender stalk Whatever Earth all-bearing Mother yeilds In INDIA East or West, or middle shoare In PONTUS or the PUNIC Coast, or where ALCINOUS reign'd, fruit of all kindes, in coate, Rough, or smooth rin'd, or bearded husk, or shell She gathers, Tribute large, and on the board Heaps with unsparing hand; for drink the Grape She crushes, inoffensive moust, and meathes From many a berrie, and from sweet kernels prest She tempers dulcet creams, nor these to hold Wants her fit vessels pure, then strews the ground With Rose and Odours from the shrub unfum'd. Mean while our Primitive great Sire, to meet His god-like Guest, walks forth, without more train Accompani'd then with his own compleat Perfections, in himself was all his state, More solemn then the tedious pomp that waits On Princes, when thir rich Retinue long Of Horses led, and Grooms besmeard with Gold Dazles the croud, and sets them all agape. Neerer his presence ADAM though not awd, Yet with submiss approach and reverence meek, As to a superior Nature, bowing low, Thus said. Native of Heav'n, for other place None can then Heav'n such glorious shape contain; Since by descending from the Thrones above, Those happie places thou hast deignd a while To want, and honour these, voutsafe with us Two onely, who yet by sov'ran gift possess This spacious ground, in yonder shadie Bowre To rest, and what the Garden choicest bears To sit and taste, till this meridian heat Be over, and the Sun more coole decline. Whom thus the Angelic Vertue answerd milde. ADAM, I therefore came, nor art thou such Created, or such place hast here to dwell, As may not oft invite, though Spirits of Heav'n To visit thee; lead on then where thy Bowre Oreshades; for these mid-hours, till Eevning rise I have at will. So to the Silvan Lodge They came, that like POMONA'S Arbour smil'd With flourets deck't and fragrant smells; but EVE Undeckt, save with her self more lovely fair Then Wood-Nymph, or the fairest Goddess feign'd Of three that in Mount IDA naked strove, Stood to entertain her guest from Heav'n; no vaile Shee needed, Vertue-proof, no thought infirme Alterd her cheek. On whom the Angel HAILE Bestowd, the holy salutation us'd Long after to blest MARIE, second EVE. Haile Mother of Mankind, whose fruitful Womb Shall fill the World more numerous with thy Sons Then with these various fruits the Trees of God Have heap'd this Table. Rais'd of grassie terf Thir Table was, and mossie seats had round, And on her ample Square from side to side All AUTUMN pil'd, though SPRING and AUTUMN here Danc'd hand in hand. A while discourse they hold; No fear lest Dinner coole; when thus began Our Authour. Heav'nly stranger, please to taste These bounties which our Nourisher, from whom All perfet good unmeasur'd out, descends, To us for food and for delight hath caus'd The Earth to yeild; unsavourie food perhaps To spiritual Natures; only this I know, That one Celestial Father gives to all. To whom the Angel. Therefore what he gives (Whose praise be ever sung) to man in part Spiritual, may of purest Spirits be found No ingrateful food: and food alike those pure Intelligential substances require As doth your Rational; and both contain Within them every lower facultie Of sense, whereby they hear, see, smell, touch, taste, Tasting concoct, digest, assimilate, And corporeal to incorporeal turn. For know, whatever was created, needs To be sustaind and fed; of Elements The grosser feeds the purer, earth the sea, Earth and the Sea feed Air, the Air those Fires Ethereal, and as lowest first the Moon; Whence in her visage round those spots, unpurg'd Vapours not yet into her substance turnd. Nor doth the Moon no nourishment exhale From her moist Continent to higher Orbes. The Sun that light imparts to all, receives From all his alimental recompence In humid exhalations, and at Even Sups with the Ocean: though in Heav'n the Trees Of life ambrosial frutage bear, and vines Yeild Nectar, though from off the boughs each Morn We brush mellifluous Dewes, and find the ground Cover'd with pearly grain: yet God hath here Varied his bounty so with new delights, As may compare with Heaven; and to taste Think not I shall be nice. So down they sat, And to thir viands fell, nor seemingly The Angel, nor in mist, the common gloss Of Theologians, but with keen dispatch Of real hunger, and concoctive heate To transubstantiate; what redounds, transpires Through Spirits with ease; nor wonder; if by fire Of sooty coal the Empiric Alchimist Can turn, or holds it possible to turn Metals of drossiest Ore to perfet Gold As from the Mine. Mean while at Table EVE Ministerd naked, and thir flowing cups With pleasant liquors crown'd: O innocence Deserving Paradise! if ever, then, Then had the Sons of God excuse to have bin Enamour'd at that sight; but in those hearts Love unlibidinous reign'd, nor jealousie Was understood, the injur'd Lovers Hell. Thus when with meats & drinks they had suffic'd, Not burd'nd Nature, sudden mind arose In ADAM, not to let th' occasion pass Given him by this great Conference to know Of things above his World, and of thir being Who dwell in Heav'n, whose excellence he saw Transcend his own so farr, whose radiant forms Divine effulgence, whose high Power so far Exceeded human, and his wary speech Thus to th' Empyreal Minister he fram'd. Inhabitant with God, now know I well Thy favour, in this honour done to man, Under whose lowly roof thou hast voutsaf't To enter, and these earthly fruits to taste, Food not of Angels, yet accepted so, As that more willingly thou couldst not seem At Heav'ns high feasts to have fed: yet what compare? To whom the winged Hierarch repli'd. O ADAM, one Almightie is, from whom All things proceed, and up to him return, If not deprav'd from good, created all Such to perfection, one first matter all, Indu'd with various forms, various degrees Of substance, and in things that live, of life; But more refin'd, more spiritous, and pure, As neerer to him plac't or neerer tending Each in thir several active Sphears assignd, Till body up to spirit work, in bounds Proportiond to each kind. So from the root Springs lighter the green stalk, from thence the leaves More aerie, last the bright consummate floure Spirits odorous breathes: flours and thir fruit Mans nourishment, by gradual scale sublim'd To vital Spirits aspire, to animal, To intellectual, give both life and sense, Fansie and understanding, whence the soule Reason receives, and reason is her being, Discursive, or Intuitive; discourse Is oftest yours, the latter most is ours, Differing but in degree, of kind the same. Wonder not then, what God for you saw good If I refuse not, but convert, as you, To proper substance; time may come when men With Angels may participate, and find No inconvenient Diet, nor too light Fare: And from these corporal nutriments perhaps Your bodies may at last turn all to Spirit Improv'd by tract of time, and wingd ascend Ethereal, as wee, or may at choice Here or in Heav'nly Paradises dwell; If ye be found obedient, and retain Unalterably firm his love entire Whose progenie you are. Mean while enjoy Your fill what happiness this happie state Can comprehend, incapable of more. To whom the Patriarch of mankind repli'd. O favourable spirit, propitious guest, Well hast thou taught the way that might direct Our knowledge, and the scale of Nature set From center to circumference, whereon In contemplation of created things By steps we may ascend to God. But say, What meant that caution joind, IF YE BE FOUND OBEDIENT? can wee want obedience then To him, or possibly his love desert Who formd us from the dust, and plac'd us here Full to the utmost measure of what bliss Human desires can seek or apprehend? To whom the Angel. Son of Heav'n and Earth, Attend: That thou art happie, owe to God; That thou continu'st such, owe to thy self, That is, to thy obedience; therein stand. This was that caution giv'n thee; be advis'd. God made thee perfet, not immutable; And good he made thee, but to persevere He left it in thy power, ordaind thy will By nature free, not over-rul'd by Fate Inextricable, or strict necessity; Our voluntarie service he requires, Not our necessitated, such with him Findes no acceptance, nor can find, for how Can hearts, not free, be tri'd whether they serve Willing or no, who will but what they must By Destinie, and can no other choose? My self and all th' Angelic Host that stand In sight of God enthron'd, our happie state Hold, as you yours, while our obedience holds; On other surety none; freely we serve. Because wee freely love, as in our will To love or not; in this we stand or fall: And som are fall'n, to disobedience fall'n, And so from Heav'n to deepest Hell; O fall From what high state of bliss into what woe! To whom our great Progenitor. Thy words Attentive, and with more delighted eare Divine instructer, I have heard, then when Cherubic Songs by night from neighbouring Hills Aereal Music send: nor knew I not To be both will and deed created free; Yet that we never shall forget to love Our maker, and obey him whose command Single, is yet so just, my constant thoughts Assur'd me and still assure: though what thou tellst Hath past in Heav'n, som doubt within me move, But more desire to hear, if thou consent, The full relation, which must needs be strange, Worthy of Sacred silence to be heard; And we have yet large day, for scarce the Sun Hath finisht half his journey, and scarce begins His other half in the great Zone of Heav'n. Thus ADAM made request, and RAPHAEL After short pause assenting, thus began. High matter thou injoinst me, O prime of men, Sad task and hard, for how shall I relate To human sense th' invisible exploits Of warring Spirits; how without remorse The ruin of so many glorious once And perfet while they stood; how last unfould The secrets of another world, perhaps Not lawful to reveal? yet for thy good This is dispenc't, and what surmounts the reach Of human sense, I shall delineate so, By lik'ning spiritual to corporal forms, As may express them best, though what if Earth Be but the shaddow of Heav'n, and things therein Each to other like, more then on earth is thought? As yet this world was not, and CHAOS wilde Reignd where these Heav'ns now rowl, where Earth now rests Upon her Center pois'd, when on a day (For Time, though in Eternitie, appli'd To motion, measures all things durable By present, past, and future) on such day As Heav'ns great Year brings forth, th' Empyreal Host Of Angels by Imperial summons call'd, Innumerable before th' Almighties Throne Forthwith from all the ends of Heav'n appeerd Under thir Hierarchs in orders bright Ten thousand thousand Ensignes high advanc'd, Standards, and Gonfalons twixt Van and Reare Streame in the Aire, and for distinction serve Of Hierarchies, of Orders, and Degrees; Or in thir glittering Tissues bear imblaz'd Holy Memorials, acts of Zeale and Love Recorded eminent. Thus when in Orbes Of circuit inexpressible they stood, Orb within Orb, the Father infinite, By whom in bliss imbosom'd sat the Son, Amidst as from a flaming Mount, whoseop Brightness had made invisible, thus spake. Hear all ye Angels, Progenie of Light, Thrones, Dominations, Princedoms, Vertues, Powers, Hear my Decree, which unrevok't shall stand. This day I have begot whom I declare My onely Son, and on this holy Hill Him have anointed, whom ye now behold At my right hand; your Head I him appoint; And by my Self have sworn to him shall bow All knees in Heav'n, and shall confess him Lord: Under his great Vice-gerent Reign abide United as one individual Soule For ever happie: him who disobeyes Mee disobeyes, breaks union, and that day Cast out from God and blessed vision, falls Into utter darkness, deep ingulft, his place Ordaind without redemption, without end. So spake th' Omnipotent, and with his words All seemd well pleas'd, all seem'd, but were not all. That day, as other solem dayes, they spent In song and dance about the sacred Hill, Mystical dance, which yonder starrie Spheare Of Planets and of fixt in all her Wheeles Resembles nearest, mazes intricate, Eccentric, intervolv'd, yet regular Then most, when most irregular they seem: And in thir motions harmonie Divine So smooths her charming tones, that Gods own ear Listens delighted. Eevning approachd (For we have also our Eevning and our Morn, We ours for change delectable, not need) Forthwith from dance to sweet repast they turn Desirous, all in Circles as they stood, Tables are set, and on a sudden pil'd With Angels Food, and rubied Nectar flows: In Pearl, in Diamond, and massie Gold, Fruit of delicious Vines, the growth of Heav'n. They eat, they drink, and with refection sweet Are fill'd, before th' all bounteous King, who showrd With copious hand, rejoycing in thir joy. Now when ambrosial Night with Clouds exhal'd From that high mount of God, whence light & shade Spring both, the face of brightest Heav'n had changd To grateful Twilight (for Night comes not there In darker veile) and roseat Dews dispos'd All but the unsleeping eyes of God to rest, Wide over all the Plain, and wider farr Then all this globous Earth in Plain outspred, (Such are the Courts of God) Th' Angelic throng Disperst in Bands and Files thir Camp extend By living Streams among the Trees of Life, Pavilions numberless, and sudden reard, Celestial Tabernacles, where they slept Fannd with coole Winds, save those who in thir course Melodious Hymns about the sovran Throne Alternate all night long: but not so wak'd SATAN, so call him now, his former name Is heard no more Heav'n; he of the first, If not the first Arch-Angel, great in Power, In favour and praeeminence, yet fraught With envie against the Son of God, that day Honourd by his great Father, and proclaimd MESSIAH King anointed, could not beare Through pride that sight, and thought himself impaird. Deep malice thence conceiving & disdain, Soon as midnight brought on the duskie houre Friendliest to sleep and silence, he resolv'd With all his Legions to dislodge, and leave Unworshipt, unobey'd the Throne supream Contemptuous, and his next subordinate Awak'ning, thus to him in secret spake. Sleepst thou Companion dear, what sleep can close Thy eye-lids? and remembrest what Decree Of yesterday, so late hath past the lips Of Heav'ns Almightie. Thou to me thy thoughts Wast wont, I mine to thee was wont to impart; Both waking we were one; how then can now Thy sleep dissent? new Laws thou seest impos'd; New Laws from him who reigns, new minds may raise In us who serve, new Counsels, to debate What doubtful may ensue, more in this place To utter is not safe. Assemble thou Of all those Myriads which we lead the chief; Tell them that by command, ere yet dim Night Her shadowie Cloud withdraws, I am to haste, And all who under me thir Banners wave, Homeward with flying march where we possess The Quarters of the North, there to prepare Fit entertainment to receive our King The great MESSIAH, and his new commands, Who speedily through all the Hierarchies Intends to pass triumphant, and give Laws. So spake the false Arch-Angel, and infus'd Bad influence into th' unwarie brest Of his Associate; hee together calls, Or several one by one, the Regent Powers, Under him Regent, tells, as he was taught, That the most High commanding, now ere Night, Now ere dim Night had disincumberd Heav'n, The great Hierarchal Standard was to move; Tells the suggested cause, and casts between Ambiguous words and jealousies, to sound Or taint integritie; but all obey'd The wonted signal, and superior voice Of thir great Potentate; for great indeed His name, and high was his degree in Heav'n; His count'nance, as the Morning Starr that guides The starrie flock, allur'd them, and with lyes Drew after him the third part of Heav'ns Host: Mean while th' Eternal eye, whose sight discernes Abstrusest thoughts, from forth his holy Mount And from within the golden Lamps that burne Nightly before him, saw without thir light Rebellion rising, saw in whom, how spred Among the sons of Morn, what multitudes Were banded to oppose his high Decree; And smiling to his onely Son thus said. Son, thou in whom my glory I behold In full resplendence, Heir of all my might, Neerly it now concernes us to be sure Of our Omnipotence, and with what Arms We mean to hold what anciently we claim Of Deitie or Empire, such a foe Is rising, who intends to erect his Throne Equal to ours, throughout the spacious North; Nor so content, hath in his thought to trie In battel, what our Power is, or our right. Let us advise, and to this hazard draw With speed what force is left, and all imploy In our defence, lest unawares we lose This our high place, our Sanctuarie, our Hill. To whom the Son with calm aspect and cleer Light'ning Divine, ineffable, serene, Made answer. Mightie Father, thou thy foes Justly hast in derision, and secure Laugh'st at thir vain designes and tumults vain, Matter to mee of Glory, whom thir hate Illustrates, when they see all Regal Power Giv'n me to quell thir pride, and in event Know whether I be dextrous to subdue Thy Rebels, or be found the worst in Heav'n. So spake the Son, but SATAN with his Powers Farr was advanc't on winged speed, an Host Innumerable as the Starrs of Night, Or Starrs of Morning, Dew-drops, which the Sun Impearls on every leaf and every flouer. Regions they pass'd, the mightie Regencies Of Seraphim and Potentates and Thrones In thir triple Degrees, Regions to which All thy Dominion, ADAM, is no more Then what this Garden is to all the Earth, And all the Sea, from one entire globose Stretcht into Longitude; which having pass'd At length into the limits of the North They came, and SATAN to his Royal seat High on a Hill, far blazing, as a Mount Rais'd on a Mount, with Pyramids and Towrs From Diamond Quarries hew'n, & Rocks of Gold, The Palace of great LUCIFER, (so call That Structure in the Dialect of men Interpreted) which not long after, hee Affecting all equality with God, In imitation of that Mount whereon MESSIAH was declar'd in sight of Heav'n, The Mountain of the Congregation call'd; For thither he assembl'd all his Train, Pretending so commanded to consult About the great reception of thir King, Thither to come, and with calumnious Art Of counterfeted truth thus held thir ears. Thrones, Dominations, Princedomes, Vertues, Powers, If these magnific Titles yet remain Not meerly titular, since by Decree Another now hath to himself ingross't All Power, and us eclipst under the name Of King anointed, for whom all this haste Of midnight march, and hurried meeting here, This onely to consult how we may best With what may be devis'd of honours new Receive him coming to receive from us Knee-tribute yet unpaid, prostration vile, Too much to one, but double how endur'd, To one and to his image now proclaim'd? But what if better counsels might erect Our minds and teach us to cast off this Yoke? Will ye submit your necks, and chuse to bend The supple knee? ye will not, if I trust To know ye right, or if ye know your selves Natives and Sons of Heav'n possest before By none, and if not equal all, yet free, Equally free; for Orders and Degrees Jarr not with liberty, but well consist. Who can in reason then or right assume Monarchie over such as live by right His equals, if in power and splendor less, In freedome equal? or can introduce Law and Edict on us, who without law Erre not, much less for this to be our Lord, And look for adoration to th' abuse Of those Imperial Titles which assert Our being ordain'd to govern, not to serve? Thus farr his bold discourse without controule Had audience, when among the Seraphim ABDIEL, then whom none with more zeale ador'd The Deitie, and divine commands obei'd, Stood up, and in a flame of zeale severe The current of his fury thus oppos'd. O argument blasphemous, false and proud! Words which no eare ever to hear in Heav'n Expected, least of all from thee, ingrate In place thy self so high above thy Peeres. Canst thou with impious obloquie condemne The just Decree of God, pronounc't and sworn, That to his only Son by right endu'd With Regal Scepter, every Soule in Heav'n Shall bend the knee, and in that honour due Confess him rightful King? unjust thou saist Flatly unjust, to binde with Laws the free, And equal over equals to let Reigne, One over all with unsucceeded power. Shalt thou give Law to God, shalt thou dispute With him the points of libertie, who made Thee what thou art, & formd the Pow'rs of Heav'n Such as he pleasd, and circumscrib'd thir being? Yet by experience taught we know how good, And of our good, and of our dignitie How provident he is, how farr from thought To make us less, bent rather to exalt Our happie state under one Head more neer United. But to grant it thee unjust, That equal over equals Monarch Reigne: Thy self though great & glorious dost thou count, Or all Angelic Nature joind in one, Equal to him begotten Son, by whom As by his Word the mighty Father made All things, ev'n thee, and all the Spirits of Heav'n By him created in thir bright degrees, Crownd them with Glory, & to thir Glory nam'd Thrones, Dominations, Princedoms, Vertues, Powers Essential Powers, nor by his Reign obscur'd, But more illustrious made, since he the Head One of our number thus reduc't becomes, His Laws our Laws, all honour to him done Returns our own. Cease then this impious rage, And tempt not these; but hast'n to appease Th' incensed Father, and th' incensed Son, While Pardon may be found in time besought. So spake the fervent Angel, but his zeale None seconded, as out of season judg'd, Or singular and rash, whereat rejoic'd Th' Apostat, and more haughty thus repli'd. That we were formd then saist thou? & the work Of secondarie hands, by task transferd From Father to his Son? strange point and new! Doctrin which we would know whence learnt: who saw When this creation was? rememberst thou Thy making, while the Maker gave thee being? We know no time when we were not as now; Know none before us, self-begot, self-rais'd By our own quick'ning power, when fatal course Had circl'd his full Orbe, the birth mature Of this our native Heav'n, Ethereal Sons. Our puissance is our own, our own right hand Shall teach us highest deeds, by proof to try Who is our equal: then thou shalt behold Whether by supplication we intend Address, and to begirt th' Almighty Throne Beseeching or besieging. This report, These tidings carrie to th' anointed King; And fly, ere evil intercept thy flight. He said, and as the sound of waters deep Hoarce murmur echo'd to his words applause Through the infinite Host, nor less for that The flaming Seraph fearless, though alone Encompass'd round with foes, thus answerd bold. O alienate from God, O spirit accurst, Forsak'n of all good; I see thy fall Determind, and thy hapless crew involv'd In this perfidious fraud, contagion spred Both of thy crime and punishment: henceforth No more be troubl'd how to quit the yoke Of Gods MESSIAH; those indulgent Laws Will not be now voutsaf't, other Decrees Against thee are gon forth without recall; That Golden Scepter which thou didst reject Is now an Iron Rod to bruise and breake Thy disobedience. Well thou didst advise, Yet not for thy advise or threats I fly These wicked Tents devoted, least the wrauth Impendent, raging into sudden flame Distinguish not: for soon expect to feel His Thunder on thy head, devouring fire. Then who created thee lamenting learne, When who can uncreate thee thou shalt know. So spake the Seraph ABDIEL faithful found, Among the faithless, faithful only hee; Among innumerable false, unmov'd, Unshak'n, unseduc'd, unterrifi'd His Loyaltie he kept, his Love, his Zeale; Nor number, nor example with him wrought To swerve from truth, or change his constant mind Though single. From amidst them forth he passd, Long way through hostile scorn, which he susteind Superior, nor of violence fear'd aught; And with retorted scorn his back he turn'd On those proud Towrs to swift destruction doom'd. THE END OF THE FIFTH BOOK. PARADISE LOST BOOK VI. All night the dreadless Angel unpursu'd Through Heav'ns wide Champain held his way, till Morn, Wak't by the circling Hours, with rosie hand Unbarr'd the gates of Light. There is a Cave Within the Mount of God, fast by his Throne, Where light and darkness in perpetual round Lodge and dislodge by turns, which makes through Heav'n Grateful vicissitude, like Day and Night; Light issues forth, and at the other dore Obsequious darkness enters, till her houre To veile the Heav'n, though darkness there might well Seem twilight here; and now went forth the Morn Such as in highest Heav'n, arrayd in Gold Empyreal, from before her vanisht Night, Shot through with orient Beams: when all the Plain Coverd with thick embatteld Squadrons bright, Chariots and flaming Armes, and fierie Steeds Reflecting blaze on blaze, first met his view: Warr he perceav'd, warr in procinct, and found Already known what he for news had thought To have reported: gladly then he mixt Among those friendly Powers who him receav'd With joy and acclamations loud, that one That of so many Myriads fall'n, yet one Returnd not lost: On to the sacred hill They led him high applauded, and present Before the seat supream; from whence a voice From midst a Golden Cloud thus milde was heard. Servant of God, well done, well hast thou fought The better fight, who single hast maintaind Against revolted multitudes the Cause Of Truth, in word mightier then they in Armes; And for the testimonie of Truth hast born Universal reproach, far worse to beare Then violence: for this was all thy care To stand approv'd in sight of God, though Worlds Judg'd thee perverse: the easier conquest now Remains thee, aided by this host of friends, Back on thy foes more glorious to return Then scornd thou didst depart, and to subdue By force, who reason for thir Law refuse, Right reason for thir Law, and for thir King MESSIAH, who by right of merit Reigns. Goe MICHAEL of Celestial Armies Prince, And thou in Military prowess next GABRIEL, lead forth to Battel these my Sons Invincible, lead forth my armed Saints By Thousands and by Millions rang'd for fight; Equal in number to that Godless crew Rebellious, them with Fire and hostile Arms Fearless assault, and to the brow of Heav'n Pursuing drive them out from God and bliss, Into thir place of punishment, the Gulf Of TARTARUS, which ready opens wide His fiery CHAOS to receave thir fall. So spake the Sovran voice, and Clouds began To darken all the Hill, and smoak to rowl In duskie wreathes, reluctant flames, the signe Of wrauth awak't: nor with less dread the loud Ethereal Trumpet from on high gan blow: At which command the Powers Militant, That stood for Heav'n, in mighty Quadrate joyn'd Of Union irresistible, mov'd on In silence thir bright Legions, to the sound Of instrumental Harmonie that breath'd Heroic Ardor to advent'rous deeds Under thir God-like Leaders, in the Cause Of God and his MESSIAH. On they move Indissolubly firm; nor obvious Hill, Nor streit'ning Vale, nor Wood, nor Stream divides Thir perfet ranks; for high above the ground Thir march was, and the passive Air upbore Thir nimble tread; as when the total kind Of Birds in orderly array on wing Came summond over EDEN to receive Thir names of thee; so over many a tract Of Heav'n they march'd, and many a Province wide Tenfold the length of this terrene: at last Farr in th' Horizon to the North appeer'd From skirt to skirt a fierie Region, stretcht In battailous aspect, and neerer view Bristl'd with upright beams innumerable Of rigid Spears, and Helmets throng'd, and Shields Various, with boastful Argument portraid, The banded Powers of SATAN hasting on With furious expedition; for they weend That self same day by fight, or by surprize To win the Mount of God, and on his Throne To set the envier of his State, the proud Aspirer, but thir thoughts prov'd fond and vain In the mid way: though strange to us it seemd At first, that Angel should with Angel warr, And in fierce hosting meet, who wont to meet So oft in Festivals of joy and love Unanimous, as sons of one great Sire Hymning th' Eternal Father: but the shout Of Battel now began, and rushing sound Of onset ended soon each milder thought. High in the midst exalted as a God Th' Apostat in his Sun-bright Chariot sate Idol of Majestie Divine, enclos'd With Flaming Cherubim, and golden Shields; Then lighted from his gorgeous Throne, for now 'Twixt Host and Host but narrow space was left, A dreadful interval, and Front to Front Presented stood in terrible array Of hideous length: before the cloudie Van, On the rough edge of battel ere it joyn'd, SATAN with vast and haughtie strides advanc't, Came towring, armd in Adamant and Gold; ABDIEL that sight endur'd not, where he stood Among the mightiest, bent on highest deeds, And thus his own undaunted heart explores. O Heav'n! that such resemblance of the Highest Should yet remain, where faith and realtie Remain not; wherfore should not strength & might There fail where Vertue fails, or weakest prove Where boldest; though to sight unconquerable? His puissance, trusting in th' Almightie's aide, I mean to try, whose Reason I have tri'd Unsound and false; nor is it aught but just, That he who in debate of Truth hath won, Should win in Arms, in both disputes alike Victor; though brutish that contest and foule, When Reason hath to deal with force, yet so Most reason is that Reason overcome. So pondering, and from his armed Peers Forth stepping opposite, half way he met His daring foe, at this prevention more Incens't, and thus securely him defi'd. Proud, art thou met? thy hope was to have reacht The highth of thy aspiring unoppos'd, The Throne of God unguarded, and his side Abandond at the terror of thy Power Or potent tongue; fool, not to think how vain Against th' Omnipotent to rise in Arms; Who out of smallest things could without end Have rais'd incessant Armies to defeat Thy folly; or with solitarie hand Reaching beyond all limit, at one blow Unaided could have finisht thee, and whelmd Thy Legions under darkness; but thou seest All are not of thy Train; there be who Faith Prefer, and Pietie to God, though then To thee not visible, when I alone Seemd in thy World erroneous to dissent From all: my Sect thou seest, now learn too late How few somtimes may know, when thousands err. Whom the grand foe with scornful eye askance Thus answerd. Ill for thee, but in wisht houre Of my revenge, first sought for thou returnst From flight, seditious Angel, to receave Thy merited reward, the first assay Of this right hand provok't, since first that tongue Inspir'd with contradiction durst oppose A third part of the Gods, in Synod met Thir Deities to assert, who while they feel Vigour Divine within them, can allow Omnipotence to none. But well thou comst Before thy fellows, ambitious to win From me som Plume, that thy success may show Destruction to the rest: this pause between (Unanswerd least thou boast) to let thee know; At first I thought that Libertie and Heav'n To heav'nly Soules had bin all one; but now I see that most through sloth had rather serve, Ministring Spirits, traind up in Feast and Song; Such hast thou arm'd, the Minstrelsie of Heav'n, Servilitie with freedom to contend, As both thir deeds compar'd this day shall prove. To whom in brief thus ABDIEL stern repli'd. Apostat, still thou errst, nor end wilt find Of erring, from the path of truth remote: Unjustly thou deprav'st it with the name Of SERVITUDE to serve whom God ordains, Or Nature; God and Nature bid the same, When he who rules is worthiest, and excells Them whom he governs. This is servitude, To serve th' unwise, or him who hath rebelld Against his worthier, as thine now serve thee, Thy self not free, but to thy self enthrall'd; Yet leudly dar'st our ministring upbraid. Reign thou in Hell thy Kingdom, let mee serve In Heav'n God ever blessed, and his Divine Behests obey, worthiest to be obey'd, Yet Chains in Hell, not Realms expect: mean while From mee returnd, as erst thou saidst, from flight, This greeting on thy impious Crest receive. So saying, a noble stroke he lifted high, Which hung not, but so swift with tempest fell On the proud Crest of SATAN, that no sight, Nor motion of swift thought, less could his Shield Such ruin intercept: ten paces huge He back recoild; the tenth on bended knee His massie Spear upstaid; as if on Earth Winds under ground or waters forcing way Sidelong, had push't a Mountain from his seat Half sunk with all his Pines. Amazement seis'd The Rebel Thrones, but greater rage to see Thus foil'd thir mightiest, ours joy filld, and shout, Presage of Victorie and fierce desire Of Battel: whereat MICHAEL bid sound Th' Arch-Angel trumpet; through the vast of Heav'n It sounded, and the faithful Armies rung HOSANNA to the Highest: nor stood at gaze The adverse Legions, nor less hideous joyn'd The horrid shock: now storming furie rose, And clamour such as heard in Heav'n till now Was never, Arms on Armour clashing bray'd Horrible discord, and the madding Wheeles Of brazen Chariots rag'd; dire was the noise Of conflict; over head the dismal hiss Of fiery Darts in flaming volies flew, And flying vaulted either Host with fire. Sounder fierie Cope together rush'd Both Battels maine, with ruinous assault And inextinguishable rage; all Heav'n Resounded, and had Earth bin then, all Earth Had to her Center shook. What wonder? when Millions of fierce encountring Angels fought On either side, the least of whom could weild These Elements, and arm him with the force Of all thir Regions: how much more of Power Armie against Armie numberless to raise Dreadful combustion warring, and disturb, Though not destroy, thir happie Native seat; Had not th' Eternal King Omnipotent From his strong hold of Heav'n high over-rul'd And limited thir might; though numberd such As each divided Legion might have seemd A numerous Host, in strength each armed hand A Legion; led in fight, yet Leader seemd Each Warriour single as in Chief, expert When to advance, or stand, or turn the sway Of Battel, open when, and when to close The ridges of grim Warr; no thought of flight, None of retreat, no unbecoming deed That argu'd fear; each on himself reli'd, As onely in his arm the moment lay Of victorie; deeds of eternal fame Were don, but infinite: for wide was spred That Warr and various; somtimes on firm ground A standing fight, then soaring on main wing Tormented all the Air; all Air seemd then Conflicting Fire: long time in eeven scale The Battel hung; till SATAN, who that day Prodigious power had shewn, and met in Armes No equal, raunging through the dire attack Of fighting Seraphim confus'd, at length Saw where the Sword of MICHAEL smote, and fell'd Squadrons at once, with huge two-handed sway Brandisht aloft the horrid edge came down Wide wasting; such destruction to withstand He hasted, and oppos'd the rockie Orb Of tenfold Adamant, his ample Shield A vast circumference: At his approach The great Arch-Angel from his warlike toile Surceas'd, and glad as hoping here to end Intestine War in Heav'n, the arch foe subdu'd Or Captive drag'd in Chains, with hostile frown And visage all enflam'd first thus began. Author of evil, unknown till thy revolt, Unnam'd in Heav'n, now plenteous, as thou seest These Acts of hateful strife, hateful to all, Though heaviest by just measure on thy self And thy adherents: how hast thou disturb'd Heav'ns blessed peace, and into Nature brought Miserie, uncreated till the crime Of thy Rebellion? how hast thou instill'd Thy malice into thousands, once upright And faithful, now prov'd false. But think not here To trouble Holy Rest; Heav'n casts thee out From all her Confines. Heav'n the seat of bliss Brooks not the works of violence and Warr. Hence then, and evil go with thee along Thy ofspring, to the place of evil, Hell, Thou and thy wicked crew; there mingle broiles, Ere this avenging Sword begin thy doome, Or som more sudden vengeance wing'd from God Precipitate thee with augmented paine. So spake the Prince of Angels; to whom thus The Adversarie. Nor think thou with wind Of airie threats to aw whom yet with deeds Thou canst not. Hast thou turnd the least of these To flight, or if to fall, but that they rise Unvanquisht, easier to transact with mee That thou shouldst hope, imperious, & with threats To chase me hence? erre not that so shall end The strife which thou call'st evil, but wee style The strife of Glorie: which we mean to win, Or turn this Heav'n it self into the Hell Thou fablest, here however to dwell free, If not to reign: mean while thy utmost force, And join him nam'd ALMIGHTIE to thy aid, I flie not, but have sought thee farr and nigh. They ended parle, and both addrest for fight Unspeakable; for who, though with the tongue Of Angels, can relate, or to what things Liken on Earth conspicuous, that may lift Human imagination to such highth Of Godlike Power: for likest Gods they seemd, Stood they or mov'd, in stature, motion, arms Fit to decide the Empire of great Heav'n. Now wav'd thir fierie Swords, and in the Aire Made horrid Circles; two broad Suns thir Shields Blaz'd opposite, while expectation stood In horror; from each hand with speed retir'd Where erst was thickest fight, th' Angelic throng, And left large field, unsafe within the wind Of such commotion, such as to set forth Great things by small, If Natures concord broke, Among the Constellations warr were sprung, Two Planets rushing from aspect maligne Of fiercest opposition in mid Skie, Should combat, and thir jarring Sphears confound. Together both with next to Almightie Arme, Uplifted imminent one stroke they aim'd That might determine, and not need repeate, As not of power, at once; nor odds appeerd In might or swift prevention; but the sword Of MICHAEL from the Armorie of God Was giv'n him temperd so, that neither keen Nor solid might resist that edge: it met The sword of SATAN with steep force to smite Descending, and in half cut sheere, nor staid, But with swift wheele reverse, deep entring shar'd All his right side; then SATAN first knew pain, And writh'd him to and fro convolv'd; so sore The griding sword with discontinuous wound Pass'd through him, but th' Ethereal substance clos'd Not long divisible, and from the gash A stream of Nectarous humor issuing flow'd Sanguin, such as Celestial Spirits may bleed, And all his Armour staind ere while so bright. Forthwith on all sides to his aide was run By Angels many and strong, who interpos'd Defence, while others bore him on thir Shields Back to his Chariot; where it stood retir'd From off the files of warr; there they him laid Gnashing for anguish and despite and shame To find himself not matchless, and his pride Humbl'd by such rebuke, so farr beneath His confidence to equal God in power. Yet soon he heal'd; for Spirits that live throughout Vital in every part, not as frail man In Entrailes, Heart or Head, Liver or Reines, Cannot but by annihilating die; Nor in thir liquid texture mortal wound Receive, no more then can the fluid Aire: All Heart they live, all Head, all Eye, all Eare, All Intellect, all Sense, and as they please, They Limb themselves, and colour, shape or size Assume, as likes them best, condense or rare. Mean while in other parts like deeds deservd Memorial, where the might of GABRIEL fought, And with fierce Ensignes pierc'd the deep array Of MOLOC furious King, who him defi'd, And at his Chariot wheeles to drag him bound Threatn'd, nor from the Holie One of Heav'n Refrein'd his tongue blasphemous; but anon Down clov'n to the waste, with shatterd Armes And uncouth paine fled bellowing. On each wing URIEL and RAPHAEL his vaunting foe, Though huge, and in a Rock of Diamond Armd, Vanquish'd ADRAMELEC, and ASMADAI, Two potent Thrones, that to be less then Gods Disdain'd, but meaner thoughts learnd in thir flight, Mangl'd with gastly wounds through Plate and Maile. Nor stood unmindful ABDIEL to annoy The Atheist crew, but with redoubl'd blow ARIEL and ARIOC, and the violence Of RAMIEL scorcht and blasted overthrew. I might relate of thousands, and thir names Eternize here on Earth; but those elect Angels contented with thir fame in Heav'n Seek not the praise of men: the other sort In might though wondrous and in Acts of Warr, Nor of Renown less eager, yet by doome Canceld from Heav'n and sacred memorie, Nameless in dark oblivion let them dwell. For strength from Truth divided and from Just, Illaudable, naught merits but dispraise And ignominie, yet to glorie aspires Vain glorious, and through infamie seeks fame: Therfore Eternal silence be thir doome. And now thir mightiest quelld, the battel swerv'd, With many an inrode gor'd; deformed rout Enter'd, and foul disorder; all the ground With shiverd armour strow'n, and on a heap Chariot and Charioter lay overturnd And fierie foaming Steeds; what stood, recoyld Orewearied, through the faint Satanic Host Defensive scarse, or with pale fear surpris'd, Then first with fear surpris'd and sense of paine Fled ignominious, to such evil brought By sinne of disobedience, till that hour Not liable to fear or flight or paine. Far otherwise th' inviolable Saints In Cubic Phalanx firm advanc't entire, Invulnerable, impenitrably arm'd: Such high advantages thir innocence Gave them above thir foes, not to have sinnd, Not to have disobei'd; in fight they stood Unwearied, unobnoxious to be pain'd By wound, though from thir place by violence mov'd. Now Night her course began, and over Heav'n Inducing darkness, grateful truce impos'd, And silence on the odious dinn of Warr: Under her Cloudie covert both retir'd, Victor and Vanquisht: on the foughten field MICHAEL and his Angels prevalent Encamping, plac'd in Guard thir Watches round, Cherubic waving fires: on th' other part SATAN with his rebellious disappeerd, Far in the dark dislodg'd, and void of rest, His Potentates to Councel call'd by night; And in the midst thus undismai'd began. O now in danger tri'd, now known in Armes Not to be overpowerd, Companions deare, Found worthy not of Libertie alone, Too mean pretense, but what we more affect, Honour, Dominion, Glorie, and renowne, Who have sustaind one day in doubtful fight, (And if one day, why not Eternal dayes?) What Heavens Lord had powerfullest to send Against us from about his Throne, and judg'd Sufficient to subdue us to his will, But proves not so: then fallible, it seems, Of future we may deem him, though till now Omniscient thought. True is, less firmly arm'd, Some disadvantage we endur'd and paine, Till now not known, but known as soon contemnd, Since now we find this our Empyreal forme Incapable of mortal injurie Imperishable, and though peirc'd with wound, Soon closing, and by native vigour heal'd. Of evil then so small as easie think The remedie; perhaps more valid Armes, Weapons more violent, when next we meet, May serve to better us, and worse our foes, Or equal what between us made the odds, In Nature none: if other hidden cause Left them Superiour, while we can preserve Unhurt our mindes, and understanding sound, Due search and consultation will disclose. He sat; and in th' assembly next upstood NISROC, of Principalities the prime; As one he stood escap't from cruel fight, Sore toild, his riv'n Armes to havoc hewn, And cloudie in aspect thus answering spake. Deliverer from new Lords, leader to free Enjoyment of our right as Gods; yet hard For Gods, and too unequal work we find Against unequal armes to fight in paine, Against unpaind, impassive; from which evil Ruin must needs ensue; for what availes Valour or strength, though matchless, quelld with pain Which all subdues, and makes remiss the hands Of Mightiest. Sense of pleasure we may well Spare out of life perhaps, and not repine, But live content, which is the calmest life: But pain is perfet miserie, the worst Of evils, and excessive, overturnes All patience. He who therefore can invent With what more forcible we may offend Our yet unwounded Enemies, or arme Our selves with like defence, to mee deserves No less then for deliverance what we owe. Whereto with look compos'd SATAN repli'd. Not uninvented that, which thou aright Beleivst so main to our success, I bring; Which of us who beholds the bright surface Of this Ethereous mould whereon we stand, This continent of spacious Heav'n, adornd With Plant, Fruit, Flour Ambrosial, Gemms & Gold, Whose Eye so superficially surveyes These things, as not to mind from whence they grow Deep under ground, materials dark and crude, Of spiritous and fierie spume, till toucht With Heav'ns ray, and temperd they shoot forth So beauteous, op'ning to the ambient light. These in thir dark Nativitie the Deep Shall yeild us, pregnant with infernal flame, Which into hallow Engins long and round Thick-rammd, at th' other bore with touch of fire Dilated and infuriate shall send forth From far with thundring noise among our foes Such implements of mischief as shall dash To pieces, and orewhelm whatever stands Adverse, that they shall fear we have disarmd The Thunderer of his only dreaded bolt. Nor long shall be our labour, yet ere dawne, Effect shall end our wish. Mean while revive; Abandon fear; to strength and counsel joind Think nothing hard, much less to be despaird. He ended, and his words thir drooping chere Enlightn'd, and thir languisht hope reviv'd. Th' invention all admir'd, and each, how hee To be th' inventer miss'd, so easie it seemd Once found, which yet unfound most would have thought Impossible: yet haply of thy Race In future dayes, if Malice should abound, Some one intent on mischief, or inspir'd With dev'lish machination might devise Like instrument to plague the Sons of men For sin, on warr and mutual slaughter bent. Forthwith from Councel to the work they flew, None arguing stood, innumerable hands Were ready, in a moment up they turnd Wide the Celestial soile, and saw beneath Th' originals of Nature in thir crude Conception; Sulphurous and Nitrous Foame They found, they mingl'd, and with suttle Art, Concocted and adusted they reduc'd To blackest grain, and into store conveyd: Part hidd'n veins diggd up (nor hath this Earth Entrails unlike) of Mineral and Stone, Whereof to found thir Engins and thir Balls Of missive ruin; part incentive reed Provide, pernicious with one touch to fire. So all ere day spring, under conscious Night Secret they finish'd, and in order set, With silent circumspection unespi'd. Now when fair Morn Orient in Heav'n appeerd Up rose the Victor Angels, and to Arms The matin Trumpet Sung: in Arms they stood Of Golden Panoplie, refulgent Host, Soon banded; others from the dawning Hills Lookd round, and Scouts each Coast light-armed scoure, Each quarter, to descrie the distant foe, Where lodg'd, or whither fled, or if for fight, In motion or in alt: him soon they met Under spred Ensignes moving nigh, in slow But firm Battalion; back with speediest Sail ZEPHIEL, of Cherubim the swiftest wing, Came flying, and in mid Aire aloud thus cri'd. Arme, Warriours, Arme for fight, the foe at hand, Whom fled we thought, will save us long pursuit This day, fear not his flight; so thick a Cloud He comes, and settl'd in his face I see Sad resolution and secure: let each His Adamantine coat gird well, and each Fit well his Helme, gripe fast his orbed Shield, Born eevn or high, for this day will pour down, If I conjecture aught, no drizling showr, But ratling storm of Arrows barbd with fire. So warnd he them aware themselves, and soon In order, quit of all impediment; Instant without disturb they took Allarm, And onward move Embattelld; when behold Not distant far with heavie pace the Foe Approaching gross and huge; in hollow Cube Training his devilish Enginrie, impal'd On every side with shaddowing Squadrons Deep, To hide the fraud. At interview both stood A while, but suddenly at head appeerd SATAN: And thus was heard Commanding loud. Vangard, to Right and Left the Front unfould; That all may see who hate us, how we seek Peace and composure, and with open brest Stand readie to receive them, if they like Our overture, and turn not back perverse; But that I doubt, however witness Heaven, Heav'n witness thou anon, while we discharge Freely our part: yee who appointed stand Do as you have in charge, and briefly touch What we propound, and loud that all may hear. So scoffing in ambiguous words, he scarce Had ended; when to Right and Left the Front Divided, and to either Flank retir'd. Which to our eyes discoverd new and strange, A triple-mounted row of Pillars laid On Wheels (for like to Pillars most they seem'd Or hollow'd bodies made of Oak or Firr With branches lopt, in Wood or Mountain fell'd) Brass, Iron, Stonie mould, had not thir mouthes With hideous orifice gap't on us wide, Portending hollow truce; at each behind A Seraph stood, and in his hand a Reed Stood waving tipt with fire; while we suspense, Collected stood within our thoughts amus'd, Not long, for sudden all at once thir Reeds Put forth, and to a narrow vent appli'd With nicest touch. Immediate in a flame, But soon obscur'd with smoak, all Heav'n appeerd, From those deep-throated Engins belcht, whose roar Emboweld with outragious noise the Air, And all her entrails tore, disgorging foule Thir devillish glut, chaind Thunderbolts and Hail Of Iron Globes, which on the Victor Host Level'd, with such impetuous furie smote, That whom they hit, none on thir feet might stand, Though standing else as Rocks, but down they fell By thousands, Angel on Arch-Angel rowl'd; The sooner for thir Arms, unarm'd they might Have easily as Spirits evaded swift By quick contraction or remove; but now Foule dissipation follow'd and forc't rout; Nor serv'd it to relax thir serried files. What should they do? if on they rusht, repulse Repeated, and indecent overthrow Doubl'd, would render them yet more despis'd, And to thir foes a laughter; for in view Stood rankt of Seraphim another row In posture to displode thir second tire Of Thunder: back defeated to return They worse abhorr'd. SATAN beheld thir plight, And to his Mates thus in derision call'd. O Friends, why come not on these Victors proud? Ere while they fierce were coming, and when wee, To entertain them fair with open Front And Brest, (what could we more?) propounded terms Of composition, strait they chang'd thir minds, Flew off, and into strange vagaries fell, As they would dance, yet for a dance they seemd Somwhat extravagant and wilde, perhaps For joy of offerd peace: but I suppose If our proposals once again were heard We should compel them to a quick result. To whom thus BELIAL in like gamesom mood. Leader, the terms we sent were terms of weight, Of hard contents, and full of force urg'd home, Such as we might perceive amus'd them all, And stumbl'd many, who receives them right, Had need from head to foot well understand; Not understood, this gift they have besides, They shew us when our foes walk not upright. So they among themselves in pleasant veine Stood scoffing, highthn'd in thir thoughts beyond All doubt of Victorie, eternal might To match with thir inventions they presum'd So easie, and of his Thunder made a scorn, And all his Host derided, while they stood A while in trouble; but they stood not long, Rage prompted them at length, & found them arms Against such hellish mischief fit to oppose. Forthwith (behold the excellence, the power Which God hath in his mighty Angels plac'd) Thir Arms away they threw, and to the Hills (For Earth hath this variety from Heav'n Of pleasure situate in Hill and Dale) Light as the Lightning glimps they ran, they flew, From thir foundations loosning to and fro They pluckt the seated Hills with all thir load, Rocks, Waters, Woods, and by the shaggie tops Up lifting bore them in thir hands: Amaze, Be sure, and terrour seis'd the rebel Host, When coming towards them so dread they saw The bottom of the Mountains upward turn'd, Till on those cursed Engins triple-row They saw them whelmd, and all thir confidence Under the weight of Mountains buried deep, Themselves invaded next, and on thir heads Main Promontories flung, which in the Air Came shadowing, and opprest whole Legions arm'd, Thir armor help'd thir harm, crush't in and brus'd Into thir substance pent, which wrought them pain Implacable, and many a dolorous groan, Long strugling underneath, ere they could wind Out of such prison, though Spirits of purest light, Purest at first, now gross by sinning grown. The rest in imitation to like Armes Betook them, and the neighbouring Hills uptore; So Hills amid the Air encounterd Hills Hurl'd to and fro with jaculation dire, That under ground they fought in dismal shade; Infernal noise; Warr seem'd a civil Game To this uproar; horrid confusion heapt Upon confusion rose: and now all Heav'n Had gone to wrack, with ruin overspred, Had not th' Almightie Father where he sits Shrin'd in his Sanctuarie of Heav'n secure, Consulting on the sum of things, foreseen This tumult, and permitted all, advis'd: That his great purpose he might so fulfill, To honour his Anointed Son aveng'd Upon his enemies, and to declare All power on him transferr'd: whence to his Son Th' Assessor of his Throne he thus began. Effulgence of my Glorie, Son belov'd, Son in whose face invisible is beheld Visibly, what by Deitie I am, And in whose hand what by Decree I doe, Second Omnipotence, two dayes are past, Two dayes, as we compute the dayes of Heav'n, Since MICHAEL and his Powers went forth to tame These disobedient; sore hath been thir fight, As likeliest was, when two such Foes met arm'd; For to themselves I left them, and thou knowst, Equal in their Creation they were form'd, Save what sin hath impaird, which yet hath wrought Insensibly, for I suspend thir doom; Whence in perpetual fight they needs must last Endless, and no solution will be found: Warr wearied hath perform'd what Warr can do, And to disorder'd rage let loose the reines, With Mountains as with Weapons arm'd, which makes Wild work in Heav'n, and dangerous to the maine. Two dayes are therefore past, the third is thine; For thee I have ordain'd it, and thus farr Have sufferd, that the Glorie may be thine Of ending this great Warr, since none but Thou Can end it. Into thee such Vertue and Grace Immense I have transfus'd, that all may know In Heav'n and Hell thy Power above compare, And this perverse Commotion governd thus, To manifest thee worthiest to be Heir Of all things, to be Heir and to be King By Sacred Unction, thy deserved right. Go then thou Mightiest in thy Fathers might, Ascend my Chariot, guide the rapid Wheeles That shake Heav'ns basis, bring forth all my Warr, My Bow and Thunder, my Almightie Arms Gird on, and Sword upon thy puissant Thigh; Pursue these sons of Darkness, drive them out From all Heav'ns bounds into the utter Deep: There let them learn, as likes them, to despise God and MESSIAH his anointed King. He said, and on his Son with Rayes direct Shon full, he all his Father full exprest Ineffably into his face receiv'd, And thus the filial Godhead answering spake. O Father, O Supream of heav'nly Thrones, First, Highest, Holiest, Best, thou alwayes seekst To glorifie thy Son, I alwayes thee, As is most just; this I my Glorie account, My exaltation, and my whole delight, That thou in me well pleas'd, declarst thy will Fulfill'd, which to fulfil is all my bliss. Scepter and Power, thy giving, I assume, And gladlier shall resign, when in the end Thou shalt be All in All, and I in thee For ever, and in mee all whom thou lov'st: But whom thou hat'st, I hate, and can put on Thy terrors, as I put thy mildness on, Image of thee in all things; and shall soon, Armd with thy might, rid heav'n of these rebell'd, To thir prepar'd ill Mansion driven down To chains of Darkness, and th' undying Worm, That from thy just obedience could revolt, Whom to obey is happiness entire. Then shall thy Saints unmixt, and from th' impure Farr separate, circling thy holy Mount Unfained HALLELUIAHS to thee sing, Hymns of high praise, and I among them chief. So said, he o're his Scepter bowing, rose From the right hand of Glorie where he sate, And the third sacred Morn began to shine Dawning through Heav'n: forth rush'd with whirlwind sound The Chariot of Paternal Deitie, Flashing thick flames, Wheele within Wheele undrawn, It self instinct with Spirit, but convoyd By four Cherubic shapes, four Faces each Had wondrous, as with Starrs thir bodies all And Wings were set with Eyes, with Eyes the Wheels Of Beril, and careering Fires between; Over thir heads a chrystal Firmament, Whereon a Saphir Throne, inlaid with pure Amber, and colours of the showrie Arch. Hee in Celestial Panoplie all armd Of radiant URIM, work divinely wrought, Ascended, at his right hand Victorie Sate Eagle-wing'd, beside him hung his Bow And Quiver with three-bolted Thunder stor'd, And from about him fierce Effusion rowld Of smoak and bickering flame, and sparkles dire; Attended with ten thousand thousand Saints, He onward came, farr off his coming shon, And twentie thousand (I thir number heard) Chariots of God, half on each hand were seen: Hee on the wings of Cherub rode sublime On the Crystallin Skie, in Saphir Thron'd. Illustrious farr and wide, but by his own First seen, them unexpected joy surpriz'd, When the great Ensign of MESSIAH blaz'd Aloft by Angels born, his Sign in Heav'n: Under whose Conduct MICHAEL soon reduc'd His Armie, circumfus'd on either Wing, Under thir Head imbodied all in one. Before him Power Divine his way prepar'd; At his command the uprooted Hills retir'd Each to his place, they heard his voice and went Obsequious, Heav'n his wonted face renewd, And with fresh Flourets Hill and Valley smil'd. This saw his hapless Foes, but stood obdur'd, And to rebellious fight rallied thir Powers Insensate, hope conceiving from despair. In heav'nly Spirits could such perverseness dwell? But to convince the proud what Signs availe, Or Wonders move th' obdurate to relent? They hard'nd more by what might most reclame, Grieving to see his Glorie, at the sight Took envie, and aspiring to his highth, Stood reimbattell'd fierce, by force or fraud Weening to prosper, and at length prevaile Against God and MESSIAH, or to fall In universal ruin last, and now To final Battel drew, disdaining flight, Or faint retreat; when the great Son of God To all his Host on either hand thus spake. Stand still in bright array ye Saints, here stand Ye Angels arm'd, this day from Battel rest; Faithful hath been your Warfare, and of God Accepted, fearless in his righteous Cause, And as ye have receivd, so have ye don Invincibly; but of this cursed crew The punishment to other hand belongs, Vengeance is his, or whose he sole appoints; Number to this dayes work is not ordain'd Nor multitude, stand onely and behold Gods indignation on these Godless pourd By mee; not you but mee they have despis'd, Yet envied; against mee is all thir rage, Because the Father, t' whom in Heav'n supream Kingdom and Power and Glorie appertains, Hath honourd me according to his will. Therefore to mee thir doom he hath assig'n'd; That they may have thir wish, to trie with mee In Battel which the stronger proves, they all, Or I alone against them, since by strength They measure all, of other excellence Not emulous, nor care who them excells; Nor other strife with them do I voutsafe. So spake the Son, and into terrour chang'd His count'nance too severe to be beheld And full of wrauth bent on his Enemies. At once the Four spred out thir Starrie wings With dreadful shade contiguous, and the Orbes Of his fierce Chariot rowld, as with the sound Of torrent Floods, or of a numerous Host. Hee on his impious Foes right onward drove, Gloomie as Night; under his burning Wheeles The stedfast Empyrean shook throughout, All but the Throne it self of God. Full soon Among them he arriv'd; in his right hand Grasping ten thousand Thunders, which he sent Before him, such as in thir Soules infix'd Plagues; they astonisht all resistance lost, All courage; down thir idle weapons drop'd; O're Shields and Helmes, and helmed heads he rode Of Thrones and mighty Seraphim prostrate, That wish'd the Mountains now might be again Thrown on them as a shelter from his ire. Nor less on either side tempestuous fell His arrows, from the fourfold-visag'd Foure, Distinct with eyes, and from the living Wheels, Distinct alike with multitude of eyes, One Spirit in them rul'd, and every eye Glar'd lightning, and shot forth pernicious fire Among th' accurst, that witherd all thir strength, And of thir wonted vigour left them draind, Exhausted, spiritless, afflicted, fall'n. Yet half his strength he put not forth, but check'd His Thunder in mid Volie, for he meant Not to destroy, but root them out of Heav'n: The overthrown he rais'd, and as a Heard Of Goats or timerous flock together throngd Drove them before him Thunder-struck, pursu'd With terrors and with furies to the bounds And Chrystall wall of Heav'n, which op'ning wide, Rowld inward, and a spacious Gap disclos'd Into the wastful Deep; the monstrous sight Strook them with horror backward, but far worse Urg'd them behind; headlong themselvs they threw Down from the verge of Heav'n, Eternal wrauth Burnt after them to the bottomless pit. Hell heard th' unsufferable noise, Hell saw Heav'n ruining from Heav'n and would have fled Affrighted; but strict Fate had cast too deep Her dark foundations, and too fast had bound. Nine dayes they fell; confounded CHAOS roard, And felt tenfold confusion in thir fall Through his wilde Anarchie, so huge a rout Incumberd him with ruin: Hell at last Yawning receavd them whole, and on them clos'd, Hell thir fit habitation fraught with fire Unquenchable, the house of woe and paine. Disburd'nd Heav'n rejoic'd, and soon repaird Her mural breach, returning whence it rowld. Sole Victor from th' expulsion of his Foes MESSIAH his triumphal Chariot turnd: To meet him all his Saints, who silent stood Eye witnesses of his Almightie Acts, With Jubilie advanc'd; and as they went, Shaded with branching Palme, each order bright, Sung Triumph, and him sung Victorious King, Son, Heire, and Lord, to him Dominion giv'n, Worthiest to Reign: he celebrated rode Triumphant through mid Heav'n, into the Courts And Temple of his mightie Father Thron'd On high; who into Glorie him receav'd, Where now he sits at the right hand of bliss. Thus measuring things in Heav'n by things on Earth At thy request, and that thou maist beware By what is past, to thee I have reveal'd What might have else to human Race bin hid; The discord which befel, and Warr in Heav'n Among th' Angelic Powers, and the deep fall Of those too high aspiring, who rebelld With SATAN, hee who envies now thy state, Who now is plotting how he may seduce Thee also from obedience, that with him Bereavd of happiness thou maist partake His punishment, Eternal miserie; Which would be all his solace and revenge, As a despite don against the most High, Thee once to gaine Companion of his woe. But list'n not to his Temptations, warne Thy weaker; let it profit thee to have heard By terrible Example the reward Of disobedience; firm they might have stood, Yet fell; remember, and fear to transgress. THE END OF THE SIXTH BOOK. PARADISE LOST. BOOK VII. Descend from Heav'n URANIA, by that name If rightly thou art call'd, whose Voice divine Following, above th' OLYMPIAN Hill I soare, Above the flight of PEGASEAN wing. The meaning, not the Name I call: for thou Nor of the Muses nine, nor on the top Of old OLYMPUS dwell'st, but Heav'nlie borne, Before the Hills appeerd, or Fountain flow'd, Thou with Eternal wisdom didst converse, Wisdom thy Sister, and with her didst play In presence of th' Almightie Father, pleas'd With thy Celestial Song. Up led by thee Into the Heav'n of Heav'ns I have presum'd, An Earthlie Guest, and drawn Empyreal Aire, Thy tempring; with like safetie guided down Return me to my Native Element: Least from this flying Steed unrein'd, (as once BELLEROPHON, though from a lower Clime) Dismounted, on th' ALEIAN Field I fall Erroneous, there to wander and forlorne. Half yet remaines unsung, but narrower bound Within the visible Diurnal Spheare; Standing on Earth, not rapt above the Pole, More safe I Sing with mortal voice, unchang'd To hoarce or mute, though fall'n on evil dayes, On evil dayes though fall'n, and evil tongues; In darkness, and with dangers compast rouud, And solitude; yet not alone, while thou Visit'st my slumbers Nightly, or when Morn Purples the East: still govern thou my Song, URANIA, and fit audience find, though few. But drive farr off the barbarous dissonance Of BACCHUS and his Revellers, the Race Of that wilde Rout that tore the THRACIAN Bard In RHODOPE, where Woods and Rocks had Eares To rapture, till the savage clamor dround Both Harp and Voice; nor could the Muse defend Her Son. So fail not thou, who thee implores: For thou art Heav'nlie, shee an empty dreame. Say Goddess, what ensu'd when RAPHAEL, The affable Arch-angel, had forewarn'd ADAM by dire example to beware Apostasie, by what befell in Heaven To those Apostates, least the like befall In Paradise to ADAM or his Race, Charg'd not to touch the interdicted Tree, If they transgress, and slight that sole command, So easily obeyd amid the choice Of all tasts else to please thir appetite, Though wandring. He with his consorted EVE The storie heard attentive, and was fill'd With admiration, and deep Muse to heare Of things so high and strange, things to thir thought So unimaginable as hate in Heav'n, And Warr so neer the Peace of God in bliss With such confusion: but the evil soon Driv'n back redounded as a flood on those From whom it sprung, impossible to mix With Blessedness. Whence ADAM soon repeal'd The doubts that in his heart arose: and now Led on, yet sinless, with desire to know What neerer might concern him, how this World Of Heav'n and Earth conspicuous first began, When, and whereof created, for what cause, What within EDEN or without was done Before his memorie, as one whose drouth Yet scarce allay'd still eyes the current streame, Whose liquid murmur heard new thirst excites, Proceeded thus to ask his Heav'nly Guest. Great things, and full of wonder in our eares, Farr differing from this World, thou hast reveal'd Divine Interpreter, by favour sent Down from the Empyrean to forewarne Us timely of what might else have bin our loss, Unknown, which human knowledg could not reach: For which to the infinitly Good we owe Immortal thanks, and his admonishment Receave with solemne purpose to observe Immutably his sovran will, the end Of what we are. But since thou hast voutsaf't Gently for our instruction to impart Things above Earthly thought, which yet concernd Our knowing, as to highest wisdom seemd, Deign to descend now lower, and relate What may no less perhaps availe us known, How first began this Heav'n which we behold Distant so high, with moving Fires adornd Innumerable, and this which yeelds or fills All space, the ambient Aire wide interfus'd Imbracing round this florid Earth, what cause Mov'd the Creator in his holy Rest Through all Eternitie so late to build In CHAOS, and the work begun, how soon Absolv'd, if unforbid thou maist unfould What wee, not to explore the secrets aske Of his Eternal Empire, but the more To magnifie his works, the more we know. And the great Light of Day yet wants to run Much of his Race though steep, suspens in Heav'n Held by thy voice, thy potent voice he heares, And longer will delay to heare thee tell His Generation, and the rising Birth Of Nature from the unapparent Deep: Or if the Starr of Eevning and the Moon Haste to thy audience, Night with her will bring Silence, and Sleep listning to thee will watch, Or we can bid his absence, till thy Song End, and dismiss thee ere the Morning shine. Thus ADAM his illustrous Guest besought: And thus the Godlike Angel answerd milde. This also thy request with caution askt Obtaine: though to recount Almightie works What words or tongue of Seraph can suffice, Or heart of man suffice to comprehend? Yet what thou canst attain, which best may serve To glorifie the Maker, and inferr Thee also happier, shall not be withheld Thy hearing, such Commission from above I have receav'd, to answer thy desire Of knowledge within bounds; beyond abstain To ask, nor let thine own inventions hope Things not reveal'd, which th' invisible King, Onely Omniscient, hath supprest in Night, To none communicable in Earth or Heaven: Anough is left besides to search and know. But Knowledge is as food, and needs no less Her Temperance over Appetite, to know In measure what the mind may well contain, Oppresses else with Surfet, and soon turns Wisdom to Folly, as Nourishment to Winde. Know then, that after LUCIFER from Heav'n (So call him, brighter once amidst the Host Of Angels, then that Starr the Starrs among) Fell with his flaming Legions through the Deep Into his place, and the great Son returnd Victorious with his Saints, th' Omnipotent Eternal Father from his Throne beheld Thir multitude, and to his Son thus spake. At least our envious Foe hath fail'd, who thought All like himself rebellious, by whose aid This inaccessible high strength, the seat Of Deitie supream, us dispossest, He trusted to have seis'd, and into fraud Drew many, whom thir place knows here no more; Yet farr the greater part have kept, I see, Thir station, Heav'n yet populous retaines Number sufficient to possess her Realmes Though wide, and this high Temple to frequent With Ministeries due and solemn Rites: But least his heart exalt him in the harme Already done, to have dispeopl'd Heav'n, My damage fondly deem'd, I can repaire That detriment, if such it be to lose Self-lost, and in a moment will create Another World, out of one man a Race Of men innumerable, there to dwell, Not here, till by degrees of merit rais'd They open to themselves at length the way Up hither, under long obedience tri'd, And Earth be chang'd to Heavn, & Heav'n to Earth, One Kingdom, Joy and Union without end. Mean while inhabit laxe, ye Powers of Heav'n, And thou my Word, begotten Son, by thee This I perform, speak thou, and be it don: My overshadowing Spirit and might with thee I send along, ride forth, and bid the Deep Within appointed bounds be Heav'n and Earth, Boundless the Deep, because I am who fill Infinitude, nor vacuous the space. Though I uncircumscrib'd my self retire, And put not forth my goodness, which is free To act or not, Necessitie and Chance Approach not mee, and what I will is Fate. So spake th' Almightie, and to what he spake His Word, the Filial Godhead, gave effect. Immediate are the Acts of God, more swift Then time or motion, but to human ears Cannot without process of speech be told, So told as earthly notion can receave. Great triumph and rejoycing was in Heav'n When such was heard declar'd the Almightie's will; Glorie they sung to the most High, good will To future men, and in thir dwellings peace: Glorie to him whose just avenging ire Had driven out th' ungodly from his sight And th' habitations of the just; to him Glorie and praise, whose wisdom had ordain'd Good out of evil to create, in stead Of Spirits maligne a better Race to bring Into thir vacant room, and thence diffuse His good to Worlds and Ages infinite. So sang the Hierarchies: Mean while the Son On his great Expedition now appeer'd, Girt with Omnipotence, with Radiance crown'd Of Majestie Divine, Sapience and Love Immense, and all his Father in him shon. About his Chariot numberless were pour'd Cherub and Seraph, Potentates and Thrones, And Vertues, winged Spirits, and Chariots wing'd, From the Armoury of God, where stand of old Myriads between two brazen Mountains lodg'd Against a solemn day, harnest at hand, Celestial Equipage; and now came forth Spontaneous, for within them Spirit livd, Attendant on thir Lord: Heav'n op'nd wide Her ever during Gates, Harmonious sound On golden Hinges moving, to let forth The King of Glorie in his powerful Word And Spirit coming to create new Worlds. On heav'nly ground they stood, and from the shore They view'd the vast immeasurable Abyss Outrageous as a Sea, dark, wasteful, wilde, Up from the bottom turn'd by furious windes And surging waves, as Mountains to assault Heav'ns highth, and with the Center mix the Pole. Silence, ye troubl'd waves, and thou Deep, peace, Said then th' Omnific Word, your discord end: Nor staid, but on the Wings of Cherubim Uplifted, in Paternal Glorie rode Farr into CHAOS, and the World unborn; For CHAOS heard his voice: him all his Traine Follow'd in bright procession to behold Creation, and the wonders of his might. Then staid the fervid Wheeles, and in his hand He took the golden Compasses, prepar'd In Gods Eternal store, to circumscribe This Universe, and all created things: One foot he center'd, and the other turn'd Round through the vast profunditie obscure, And said, thus farr extend, thus farr thy bounds, This be thy just Circumference, O World. Thus God the Heav'n created, thus the Earth, Matter unform'd and void: Darkness profound Cover'd th' Abyss: but on the watrie calme His brooding wings the Spirit of God outspred, And vital vertue infus'd, and vital warmth Throughout the fluid Mass, but downward purg'd The black tartareous cold infernal dregs Adverse to life: then founded, then conglob'd Like things to like, the rest to several place Disparted, and between spun out the Air, And Earth self-ballanc't on her Center hung. Let ther be Light, said God, and forthwith Light Ethereal, first of things, quintessence pure Sprung from the Deep, and from her Native East To journie through the airie gloom began, Sphear'd in a radiant Cloud, for yet the Sun Was not; shee in a cloudie Tabernacle Sojourn'd the while. God saw the Light was good; And light from darkness by the Hemisphere Divided: Light the Day, and Darkness Night He nam'd. Thus was the first Day Eev'n and Morn: Nor past uncelebrated, nor unsung By the Celestial Quires, when Orient Light Exhaling first from Darkness they beheld; Birth-day of Heav'n and Earth; with joy and shout The hollow Universal Orb they fill'd, And touch't thir Golden Harps, & hymning prais'd God and his works, Creatour him they sung, Both when first Eevning was, and when first Morn. Again, God said, let ther be Firmament Amid the Waters, and let it divide The Waters from the Waters: and God made The Firmament, expanse of liquid, pure, Transparent, Elemental Air, diffus'd In circuit to the uttermost convex Of this great Round: partition firm and sure, The Waters underneath from those above Dividing: for as Earth, so hee the World Built on circumfluous Waters calme, in wide Crystallin Ocean, and the loud misrule Of CHAOS farr remov'd, least fierce extreames Contiguous might distemper the whole frame: And Heav'n he nam'd the Firmament: So Eev'n And Morning CHORUS sung the second Day. The Earth was form'd, but in the Womb as yet Of Waters, Embryon immature involv'd, Appeer'd not: over all the face of Earth Main Ocean flow'd, not idle, but with warme Prolific humour soft'ning all her Globe, Fermented the great Mother to conceave, Satiate with genial moisture, when God said Be gather'd now ye Waters under Heav'n Into one place, and let dry Land appeer. Immediately the Mountains huge appeer Emergent, and thir broad bare backs upheave Into the Clouds, thir tops ascend the Skie: So high as heav'd the tumid Hills, so low Down sunk a hollow bottom broad and deep, Capacious bed of Waters: thither they Hasted with glad precipitance, uprowld As drops on dust conglobing from the drie; Part rise in crystal Wall, or ridge direct, For haste; such flight the great command impress'd On the swift flouds: as Armies at the call Of Trumpet (for of Armies thou hast heard) Troop to thir Standard, so the watrie throng, Wave rowling after Wave, where way they found, If steep, with torrent rapture, if through Plaine, Soft-ebbing; nor withstood them Rock or Hill, But they, or under ground, or circuit wide With Serpent errour wandring, found thir way, And on the washie Oose deep Channels wore; Easie, e're God had bid the ground be drie, All but within those banks, where Rivers now Stream, and perpetual draw thir humid traine. The dry Land, Earth, and the great receptacle Of congregated Waters he call'd Seas: And saw that it was good, and said, Let th' Earth Put forth the verdant Grass, Herb yeilding Seed, And Fruit Tree yeilding Fruit after her kind; Whose Seed is in her self upon the Earth. He scarce had said, when the bare Earth, till then Desert and bare, unsightly, unadorn'd, Brought forth the tender Grass, whose verdure clad Her Universal Face with pleasant green, Then Herbs of every leaf, that sudden flour'd Op'ning thir various colours, and made gay Her bosom smelling sweet: and these scarce blown, Forth flourish't thick the clustring Vine, forth crept The smelling Gourd, up stood the cornie Reed Embattell'd in her field: add the humble Shrub, And Bush with frizl'd hair implicit: last Rose as in Dance the stately Trees, and spred Thir branches hung with copious Fruit; or gemm'd Thir Blossoms: with high Woods the Hills were crownd, With tufts the vallies & each fountain side, With borders long the Rivers. That Earth now Seemd like to Heav'n, a seat where Gods might dwell, Or wander with delight, and love to haunt Her sacred shades: though God had yet not rain'd Upon the Earth, and man to till the ground None was, but from the Earth a dewie Mist Went up and waterd all the ground, and each Plant of the field, which e're it was in the Earth God made, and every Herb, before it grew On the green stemm; God saw that it was good: So Eev'n and Morn recorded the Third Day. Again th' Almightie spake: Let there be Lights High in th' expanse of Heaven to divide The Day from Night; and let them be for Signes, For Seasons, and for Dayes, and circling Years, And let them be for Lights as I ordaine Thir Office in the Firmament of Heav'n To give Light on the Earth; and it was so. And God made two great Lights, great for thir use To Man, the greater to have rule by Day, The less by Night alterne: and made the Starrs, And set them in the Firmament of Heav'n To illuminate the Earth, and rule the Day In thir vicissitude, and rule the Night, And Light from Darkness to divide. God saw, Surveying his great Work, that it was good: For of Celestial Bodies first the Sun A mightie Spheare he fram'd, unlightsom first, Though of Ethereal Mould: then form'd the Moon Globose, and everie magnitude of Starrs, And sowd with Starrs the Heav'n thick as a field: Of Light by farr the greater part he took, Transplanted from her cloudie Shrine, and plac'd In the Suns Orb, made porous to receive And drink the liquid Light, firm to retaine Her gather'd beams, great Palace now of Light. Hither as to thir Fountain other Starrs Repairing, in thir gold'n Urns draw Light, And hence the Morning Planet guilds his horns; By tincture or reflection they augment Thir small peculiar, though from human sight So farr remote, with diminution seen. First in his East the glorious Lamp was seen, Regent of Day, and all th' Horizon round Invested with bright Rayes, jocond to run His Longitude through Heav'ns high rode: the gray Dawn, and the PLEIADES before him danc'd Shedding sweet influence: less bright the Moon, But opposite in leveld West was set His mirror, with full face borrowing her Light From him, for other light she needed none In that aspect, and still that distance keepes Till night, then in the East her turn she shines, Revolvd on Heav'ns great Axle, and her Reign With thousand lesser Lights dividual holds, With thousand thousand Starres, that then appeer'd Spangling the Hemisphere: then first adornd With thir bright Luminaries that Set and Rose, Glad Eevning & glad Morn crownd the fourth day. And God said, let the Waters generate Reptil with Spawn abundant, living Soule: And let Fowle flie above the Earth, with wings Displayd on the op'n Firmament of Heav'n. And God created the great Whales, and each Soul living, each that crept, which plenteously The waters generated by thir kindes, And every Bird of wing after his kinde; And saw that it was good, and bless'd them, saying, Be fruitful, multiply, and in the Seas And Lakes and running Streams the waters fill; And let the Fowle be multiply'd on the Earth. Forthwith the Sounds and Seas, each Creek & Bay With Frie innumerable swarme, and Shoales Of Fish that with thir Finns and shining Scales Glide under the green Wave, in Sculles that oft Bank the mid Sea: part single or with mate Graze the Sea weed thir pasture, & through Groves Of Coral stray, or sporting with quick glance Show to the Sun thir wav'd coats dropt with Gold, Or in thir Pearlie shells at ease, attend Moist nutriment, or under Rocks thir food In jointed Armour watch: on smooth the Seale, And bended Dolphins play: part huge of bulk Wallowing unweildie, enormous in thir Gate Tempest the Ocean: there Leviathan Hugest of living Creatures, on the Deep Stretcht like a Promontorie sleeps or swimmes, And seems a moving Land, and at his Gilles Draws in, and at his Trunck spouts out a Sea. Mean while the tepid Caves, and Fens and shoares Thir Brood as numerous hatch, from the Egg that soon Bursting with kindly rupture forth disclos'd Thir callow young, but featherd soon and fledge They summ'd thir Penns, and soaring th' air sublime With clang despis'd the ground, under a cloud In prospect; there the Eagle and the Stork On Cliffs and Cedar tops thir Eyries build: Part loosly wing the Region, part more wise In common, rang'd in figure wedge thir way, Intelligent of seasons, and set forth Thir Aierie Caravan high over Sea's Flying, and over Lands with mutual wing Easing thir flight; so stears the prudent Crane Her annual Voiage, born on Windes; the Aire Floats, as they pass, fann'd with unnumber'd plumes: From Branch to Branch the smaller Birds with song Solac'd the Woods, and spred thir painted wings Till Ev'n, nor then the solemn Nightingal Ceas'd warbling, but all night tun'd her soft layes: Others on Silver Lakes and Rivers Bath'd Thir downie Brest; the Swan with Arched neck Between her white wings mantling proudly, Rowes Her state with Oarie feet: yet oft they quit The Dank, and rising on stiff Pennons, towre The mid Aereal Skie: Others on ground Walk'd firm; the crested Cock whose clarion sounds The silent hours, and th' other whose gay Traine Adorns him, colour'd with the Florid hue Of Rainbows and Starrie Eyes. The Waters thus With Fish replenisht, and the Aire with Fowle, Ev'ning and Morn solemniz'd the Fift day. The Sixt, and of Creation last arose With Eevning Harps and Mattin, when God said, Let th' Earth bring forth Fowle living in her kinde, Cattel and Creeping things, and Beast of the Earth, Each in their kinde. The Earth obey'd, and strait Op'ning her fertil Woomb teem'd at a Birth Innumerous living Creatures, perfet formes, Limb'd and full grown: out of the ground up-rose As from his Laire the wilde Beast where he wonns In Forrest wilde, in Thicket, Brake, or Den; Among the Trees in Pairs they rose, they walk'd: The Cattel in the Fields and Meddowes green: Those rare and solitarie, these in flocks Pasturing at once, and in broad Herds upsprung: The grassie Clods now Calv'd, now half appeer'd The Tawnie Lion, pawing to get free His hinder parts, then springs as broke from Bonds, And Rampant shakes his Brinded main; the Ounce, The Libbard, and the Tyger, as the Moale Rising, the crumbl'd Earth above them threw In Hillocks; the swift Stag from under ground Bore up his branching head: scarse from his mould BEHEMOTH biggest born of Earth upheav'd His vastness: Fleec't the Flocks and bleating rose, As Plants: ambiguous between Sea and Land The River Horse and scalie Crocodile. At once came forth whatever creeps the ground, Insect or Worme; those wav'd thir limber fans For wings, and smallest Lineaments exact In all the Liveries dect of Summers pride With spots of Gold and Purple, azure and green: These as a line thir long dimension drew, Streaking the ground with sinuous trace; not all Minims of Nature; some of Serpent kinde Wondrous in length and corpulence involv'd Thir Snakie foulds, and added wings. First crept The Parsimonious Emmet, provident Of future, in small room large heart enclos'd, Pattern of just equalitie perhaps Hereafter, join'd in her popular Tribes Of Commonaltie: swarming next appeer'd The Femal Bee that feeds her Husband Drone Deliciously, and builds her waxen Cells With Honey stor'd: the rest are numberless, And thou thir Natures know'st, and gav'st them Names, Needlest to thee repeaed; nor unknown The Serpent suttl'st Beast of all the field, Of huge extent somtimes, with brazen Eyes And hairie Main terrific, though to thee Not noxious, but obedient at thy call. Now Heav'n in all her Glorie shon, and rowld Her motions, as the great first-Movers hand First wheeld thir course; Earth in her rich attire Consummate lovly smil'd; Aire, Water, Earth, By Fowl, Fish, Beast, was flown, was swum, was walkt Frequent; and of the Sixt day yet remain'd; There wanted yet the Master work, the end Of all yet don; a Creature who not prone And Brute as other Creatures, but endu'd With Sanctitie of Reason, might erect His Stature, and upright with Front serene Govern the rest, self-knowing, and from thence Magnanimous to correspond with Heav'n, But grateful to acknowledge whence his good Descends, thither with heart and voice and eyes Directed in Devotion, to adore And worship God Supream, who made him chief Of all his works: therefore the Omnipotent Eternal Father (For where is not hee Present) thus to his Son audibly spake. Let us make now Man in our image, Man In our similitude, and let them rule Over the Fish and Fowle of Sea and Aire, Beast of the Field, and over all the Earth, And every creeping thing that creeps the ground. This said, he formd thee, ADAM, thee O Man Dust of the ground, and in thy nostrils breath'd The breath of Life; in his own Image hee Created thee, in the Image of God Express, and thou becam'st a living Soul. Male he created thee, but thy consort Femal for Race; then bless'd Mankinde, and said, Be fruitful, multiplie, and fill the Earth, Subdue it, and throughout Dominion hold Over Fish of the Sea, and Fowle of the Aire, And every living thing that moves on the Earth. Wherever thus created, for no place Is yet distinct by name, thence, as thou know'st He brought thee into this delicious Grove, This Garden, planted with the Trees of God, Delectable both to behold and taste; And freely all thir pleasant fruit for food Gave thee, all sorts are here that all th' Earth yeelds, Varietie without end; but of the Tree Which tasted works knowledge of Good and Evil, Thou mai'st not; in the day thou eat'st, thou di'st; Death is the penaltie impos'd, beware, And govern well thy appetite, least sin Surprise thee, and her black attendant Death. Here finish'd hee, and all that he had made View'd, and behold all was entirely good; So Ev'n and Morn accomplish'd the Sixt day: Yet not till the Creator from his work Desisting, though unwearied, up returnd Up to the Heav'n of Heav'ns his high abode, Thence to behold this new created World Th' addition of his Empire, how it shew'd In prospect from his Throne, how good, how faire, Answering his great Idea. Up he rode Followd with acclamation and the sound Symphonious of ten thousand Harpes that tun'd Angelic harmonies: the Earth, the Aire Resounded, (thou remember'st, for thou heardst) The Heav'ns and all the Constellations rung, The Planets in thir stations list'ning stood, While the bright Pomp ascended jubilant. Open, ye everlasting Gates, they sung, Open, ye Heav'ns, your living dores; let in The great Creator from his work returnd Magnificent, his Six days work, a World; Open, and henceforth oft; for God will deigne To visit oft the dwellings of just Men Delighted, and with frequent intercourse Thither will send his winged Messengers On errands of supernal Grace. So sung The glorious Train ascending: He through Heav'n, That open'd wide her blazing Portals, led To Gods Eternal house direct the way, A broad and ample rode, whose dust is Gold And pavement Starrs, as Starrs to thee appeer, Seen in the Galaxie, that Milkie way Which nightly as a circling Zone thou seest Pouderd with Starrs. And now on Earth the Seaventh Eev'ning arose in EDEN, for the Sun Was set, and twilight from the East came on, Forerunning Night; when at the holy mount Of Heav'ns high-seated top, th' Impereal Throne Of Godhead, fixt for ever firm and sure, The Filial Power arriv'd, and sate him down With his great Father (for he also went Invisible, yet staid (such priviledge Hath Omnipresence) and the work ordain'd, Author and end of all things, and from work Now resting, bless'd and hallowd the Seav'nth day, As resting on that day from all his work, But not in silence holy kept; the Harp Had work and rested not, the solemn Pipe, And Dulcimer, all Organs of sweet stop, All sounds on Fret by String or Golden Wire Temper'd soft Tunings, intermixt with Voice Choral or Unison: of incense Clouds Fuming from Golden Censers hid the Mount. Creation and the Six dayes acts they sung, Great are thy works, JEHOVAH, infinite Thy power; what thought can measure thee or tongue Relate thee; greater now in thy return Then from the Giant Angels; thee that day Thy Thunders magnifi'd; but to create Is greater then created to destroy. Who can impair thee, mighty King, or bound Thy Empire? easily the proud attempt Of Spirits apostat and thir Counsels vaine Thou hast repeld, while impiously they thought Thee to diminish, and from thee withdraw The number of thy worshippers. Who seekes To lessen thee, against his purpose serves To manifest the more thy might: his evil Thou usest, and from thence creat'st more good. Witness this new-made World, another Heav'n From Heaven Gate not farr, founded in view On the cleer HYALINE, the Glassie Sea; Of amplitude almost immense, with Starr's Numerous, and every Starr perhaps a World Of destind habitation; but thou know'st Thir seasons: among these the seat of men, Earth with her nether Ocean circumfus'd, Thir pleasant dwelling place. Thrice happie men, And sons of men, whom God hath thus advanc't, Created in his Image, there to dwell And worship him, and in reward to rule Over his Works, on Earth, in Sea, or Air, And multiply a Race of Worshippers Holy and just: thrice happie if they know Thir happiness, and persevere upright. So sung they, and the Empyrean rung, With HALLELUIAHS: Thus was Sabbath kept. And thy request think now fulfill'd, that ask'd How first this World and face of things began, And what before thy memorie was don From the beginning, that posteritie Informd by thee might know; if else thou seekst Aught, not surpassing human measure, say. To whom thus ADAM gratefully repli'd. What thanks sufficient, or what recompence Equal have I to render thee, Divine Hystorian, who thus largely hast allayd The thirst I had of knowledge, and voutsaf't This friendly condescention to relate Things else by me unsearchable, now heard VVith wonder, but delight, and, as is due, With glorie attributed to the high Creator; some thing yet of doubt remaines, VVhich onely thy solution can resolve. VVhen I behold this goodly Frame, this VVorld Of Heav'n and Earth consisting, and compute, Thir magnitudes, this Earth a spot, a graine, An Atom, with the Firmament compar'd And all her numberd Starrs, that seem to rowle Spaces incomprehensible (for such Thir distance argues and thir swift return Diurnal) meerly to officiate light Round this opacous Earth, this punctual spot, One day and night; in all thir vast survey Useless besides, reasoning I oft admire, How Nature wise and frugal could commit Such disproportions, with superfluous hand So many nobler Bodies to create, Greater so manifold to this one use, For aught appeers, and on thir Orbs impose Such restless revolution day by day Repeated, while the sedentarie Earth, That better might with farr less compass move, Serv'd by more noble then her self, attaines Her end without least motion, and receaves, As Tribute such a sumless journey brought Of incorporeal speed, her warmth and light; Speed, to describe whose swiftness Number failes. So spake our Sire, and by his count'nance seemd Entring on studious thoughts abstruse, which EVE Perceaving where she sat retir'd in sight, With lowliness Majestic from her seat, And Grace that won who saw to wish her stay, Rose, and went forth among her Fruits and Flours, To visit how they prosper'd, bud and bloom, Her Nurserie; they at her coming sprung And toucht by her fair tendance gladlier grew. Yet went she not, as not with such discourse Delighted, or not capable her eare Of what was high: such pleasure she reserv'd, ADAM relating, she sole Auditress; Her Husband the Relater she preferr'd Before the Angel, and of him to ask Chose rather; hee, she knew would intermix Grateful digressions, and solve high dispute With conjugal Caresses, from his Lip Not Words alone pleas'd her. O when meet now Such pairs, in Love and mutual Honour joyn'd? With Goddess-like demeanour forth she went; Not unattended, for on her as Queen A pomp of winning Graces waited still, And from about her shot Darts of desire Into all Eyes to wish her still in sight. And RAPHAEL now to ADAM's doubt propos'd Benevolent and facil thus repli'd. To ask or search I blame thee not, for Heav'n Is as the Book of God before thee set, Wherein to read his wondrous Works, and learne His Seasons, Hours, or Days, or Months, or Yeares: This to attain, whether Heav'n move or Earth, Imports not, if thou reck'n right, the rest From Man or Angel the great Architect Did wisely to conceal, and not divulge His secrets to be scann'd by them who ought Rather admire; or if they list to try Conjecture, he his Fabric of the Heav'ns Hath left to thir disputes, perhaps to move His laughter at thir quaint Opinions wide Hereafter, when they come to model Heav'n And calculate the Starrs, how they will weild The mightie frame, how build, unbuild, contrive To save appeerances, how gird the Sphear With Centric and Eccentric scribl'd o're, Cycle and Epicycle, Orb in Orb: Alreadie by thy reasoning this I guess, Who art to lead thy ofspring, and supposest That Bodies bright and greater should not serve The less not bright, nor Heav'n such journies run, Earth sitting still, when she alone receaves The benefit: consider first, that Great Or Bright inferrs not Excellence: the Earth Though, in comparison of Heav'n, so small, Nor glistering, may of solid good containe More plenty then the Sun that barren shines, Whose vertue on it self workes no effect, But in the fruitful Earth; there first receavd His beams, unactive else, thir vigor find. Yet not to Earth are those bright Luminaries Officious, but to thee Earths habitant. And for the Heav'ns wide Circuit, let it speak The Makers high magnificence, who built So spacious, and his Line stretcht out so farr; That Man may know he dwells not in his own; An Edifice too large for him to fill, Lodg'd in a small partition, and the rest Ordain'd for uses to his Lord best known. The swiftness of those Circles attribute, Though numberless, to his Omnipotence, That to corporeal substances could adde Speed almost Spiritual; mee thou thinkst not slow, Who since the Morning hour set out from Heav'n Where God resides, and ere mid-day arriv'd In EDEN, distance inexpressible By Numbers that have name. But this I urge, Admitting Motion in the Heav'ns, to shew Invalid that which thee to doubt it mov'd; Not that I so affirm, though so it seem To thee who hast thy dwelling here on Earth. God to remove his wayes from human sense, Plac'd Heav'n from Earth so farr, that earthly sight, If it presume, might erre in things too high, And no advantage gaine. What if the Sun Be Center to the World, and other Starrs By his attractive vertue and thir own Incited, dance about him various rounds? Thir wandring course now high, now low, then hid, Progressive, retrograde, or standing still, In six thou seest, and what if sev'nth to these The Planet Earth, so stedfast though she seem, Insensibly three different Motions move? Which else to several Sphears thou must ascribe, Mov'd contrarie with thwart obliquities, Or save the Sun his labour, and that swift Nocturnal and Diurnal rhomb suppos'd, Invisible else above all Starrs, the Wheele Of Day and Night; which needs not thy beleefe, If Earth industrious of her self fetch Day Travelling East, and with her part averse From the Suns beam meet Night, her other part Still luminous by his ray. What if that light Sent from her through the wide transpicuous aire, To the terrestrial Moon be as a Starr Enlightning her by Day, as she by Night This Earth? reciprocal, if Land be there, Feilds and Inhabitants: Her spots thou seest As Clouds, and Clouds may rain, and Rain produce Fruits in her soft'nd Soile, for some to eate Allotted there; and other Suns perhaps With thir attendant Moons thou wilt descrie Communicating Male and Femal Light, Which two great Sexes animate the World, Stor'd in each Orb perhaps with some that live. For such vast room in Nature unpossest By living Soule, desert and desolate, Onely to shine, yet scarce to contribute Each Orb a glimps of Light, conveyd so farr Down to this habitable, which returnes Light back to them, is obvious to dispute. But whether thus these things, or whether not, Whether the Sun predominant in Heav'n Rise on the Earth, or Earth rise on the Sun, Hee from the East his flaming rode begin, Or Shee from West her silent course advance With inoffensive pace that spinning sleeps On her soft Axle, while she paces Eev'n, And bears thee soft with the smooth Air along, Sollicit not thy thoughts with matters hid, Leave them to God above, him serve and feare; Of other Creatures, as him pleases best, Wherever plac't, let him dispose: joy thou In what he gives to thee, this Paradise And thy faire EVE; Heav'n is for thee too high To know what passes there; be lowlie wise: Think onely what concernes thee and thy being; Dream not of other Worlds, what Creatures there Live, in what state, condition or degree, Contented that thus farr hath been reveal'd Not of Earth onely but of highest Heav'n. To whom thus ADAM cleerd of doubt, repli'd. How fully hast thou satisfi'd mee, pure Intelligence of Heav'n, Angel serene, And freed from intricacies, taught to live, The easiest way, nor with perplexing thoughts To interrupt the sweet of Life, from which God hath bid dwell farr off all anxious cares, And not molest us, unless we our selves Seek them with wandring thoughts, and notions vaine. But apt the Mind or Fancie is to roave Uncheckt, and of her roaving is no end; Till warn'd, or by experience taught, she learne, That not to know at large of things remote From use, obscure and suttle, but to know That which before us lies in daily life, Is the prime Wisdom, what is more, is fume, Or emptiness, or fond impertinence, And renders us in things that most concerne Unpractis'd, unprepar'd, and still to seek. Therefore from this high pitch let us descend A lower flight, and speak of things at hand Useful, whence haply mention may arise Of somthing not unseasonable to ask By sufferance, and thy wonted favour deign'd. Thee I have heard relating what was don Ere my remembrance: now hear mee relate My Storie, which perhaps thou hast not heard; And Day is yet not spent; till then thou seest How suttly to detaine thee I devise, Inviting thee to hear while I relate, Fond, were it not in hope of thy reply: For while I sit with thee, I seem in Heav'n, And sweeter thy discourse is to my eare Then Fruits of Palm-tree pleasantest to thirst And hunger both, from labour, at the houre Of sweet repast; they satiate, and soon fill, Though pleasant, but thy words with Grace Divine Imbu'd, bring to thir sweetness no satietie. To whom thus RAPHAEL answer'd heav'nly meek. Nor are thy lips ungraceful, Sire of men, Nor tongue ineloquent; for God on thee Abundantly his gifts hath also pour'd, Inward and outward both, his image faire: Speaking or mute all comliness and grace Attends thee, and each word, each motion formes. Nor less think wee in Heav'n of thee on Earth Then of our fellow servant, and inquire Gladly into the wayes of God with Man: For God we see hath honour'd thee, and set On Man his equal Love: say therefore on; For I that Day was absent, as befell, Bound on a voyage uncouth and obscure, Farr on excursion toward the Gates of Hell; Squar'd in full Legion (such command we had) To see that none thence issu'd forth a spie, Or enemie, while God was in his work, Least hee incenst at such eruption bold, Destruction with Creation might have mixt. Not that they durst without his leave attempt, But us he sends upon his high behests For state, as Sovran King, and to enure Our prompt obedience. Fast we found, fast shut The dismal Gates, and barricado'd strong; But long ere our approaching heard within Noise, other then the sound of Dance or Song, Torment, and lowd lament, and furious rage. Glad we return'd up to the coasts of Light Ere Sabbath Eev'ning: so we had in charge. But thy relation now; for I attend, Pleas'd with thy words no less then thou with mine. So spake the Godlike Power, and thus our Sire. For Man to tell how human Life began Is hard; for who himself beginning knew? Desire with thee still longer to converse Induc'd me. As new wak't from soundest sleep Soft on the flourie herb I found me laid In Balmie Sweat, which with his Beames the Sun Soon dri'd, and on the reaking moisture fed. Strait toward Heav'n my wondring Eyes I turnd, And gaz'd a while the ample Skie, till rais'd By quick instinctive motion up I sprung, As thitherward endevoring, and upright Stood on my feet; about me round I saw Hill, Dale, and shadie Woods, and sunnie Plaines, And liquid Lapse of murmuring Streams; by these, Creatures that livd, and movd, and walk'd, or flew, Birds on the branches warbling; all things smil'd, With fragrance and with joy my heart oreflow'd. My self I then perus'd, and Limb by Limb Survey'd, and sometimes went, and sometimes ran With supple joints, as lively vigour led: But who I was, or where, or from what cause, Knew not; to speak I tri'd, and forthwith spake, My Tongue obey'd and readily could name What e're I saw. Thou Sun, said I, faire Light, And thou enlight'nd Earth, so fresh and gay, Ye Hills and Dales, ye Rivers, Woods, and Plaines, And ye that live and move, fair Creatures, tell, Tell, if ye saw, how came I thus, how here? Not of my self; by some great Maker then, In goodness and in power praeeminent; Tell me, how may I know him, how adore, From whom I have that thus I move and live, And feel that I am happier then I know. While thus I call'd, and stray'd I knew not whither, From where I first drew Aire, and first beheld This happie Light, when answer none return'd, On a green shadie Bank profuse of Flours Pensive I sate me down; there gentle sleep First found me, and with soft oppression seis'd My droused sense, untroubl'd, though I thought I then was passing to my former state Insensible, and forthwith to dissolve: When suddenly stood at my Head a dream, Whose inward apparition gently mov'd My Fancy to believe I yet had being, And livd: One came, methought, of shape Divine, And said, thy Mansion wants thee, ADAM, rise, First Man, of Men innumerable ordain'd First Father, call'd by thee I come thy Guide To the Garden of bliss, thy seat prepar'd. So saying, by the hand he took me rais'd, And over Fields and Waters, as in Aire Smooth sliding without step, last led me up A woodie Mountain; whose high top was plaine, A Circuit wide, enclos'd, with goodliest Trees Planted, with Walks, and Bowers, that what I saw Of Earth before scarse pleasant seemd. Each Tree Load'n with fairest Fruit, that hung to the Eye Tempting, stirr'd in me sudden appetite To pluck and eate; whereat I wak'd, and found Before mine Eyes all real, as the dream Had lively shadowd: Here had new begun My wandring, had not hee who was my Guide Up hither, from among the Trees appeer'd, Presence Divine. Rejoycing, but with aw In adoration at his feet I fell Submiss: he rear'd me, & Whom thou soughtst I am, Said mildely, Author of all this thou seest Above, or round about thee or beneath. This Paradise I give thee, count it thine To Till and keep, and of the Fruit to eate: Of every Tree that in the Garden growes Eate freely with glad heart; fear here no dearth: But of the Tree whose operation brings Knowledg of good and ill, which I have set The Pledge of thy Obedience and thy Faith, Amid the Garden by the Tree of Life, Remember what I warne thee, shun to taste, And shun the bitter consequence: for know, The day thou eat'st thereof, my sole command Transgrest, inevitably thou shalt dye; From that day mortal, and this happie State Shalt loose, expell'd from hence into a World Of woe and sorrow. Sternly he pronounc'd The rigid interdiction, which resounds Yet dreadful in mine eare, though in my choice Not to incur; but soon his cleer aspect Return'd and gratious purpose thus renew'd. Not onely these fair bounds, but all the Earth To thee and to thy Race I give; as Lords Possess it, and all things that therein live, Or live in Sea, or Aire, Beast, Fish, and Fowle. In signe whereof each Bird and Beast behold After thir kindes; I bring them to receave From thee thir Names, and pay thee fealtie With low subjection; understand the same Of Fish within thir watry residence, Not hither summond, since they cannot change Thir Element to draw the thinner Aire. As thus he spake, each Bird and Beast behold Approaching two and two, These cowring low With blandishment, each Bird stoop'd on his wing. I nam'd them, as they pass'd, and understood Thir Nature, with such knowledg God endu'd My sudden apprehension: but in these I found not what me thought I wanted still; And to the Heav'nly vision thus presum'd. O by what Name, for thou above all these, Above mankinde, or aught then mankinde higher, Surpassest farr my naming, how may I Adore thee, Author of this Universe, And all this good to man, for whose well being So amply, and with hands so liberal Thou hast provided all things: but with mee I see not who partakes. In solitude What happiness, who can enjoy alone, Or all enjoying, what contentment find? Thus I presumptuous; and the vision bright, As with a smile more bright'nd, thus repli'd. What call'st thou solitude, is not the Earth With various living creatures, and the Aire Replenisht, and all these at thy command To come and play before thee, know'st thou not Thir language and thir wayes, they also know, And reason not contemptibly; with these Find pastime, and beare rule; thy Realm is large. So spake the Universal Lord, and seem'd So ordering. I with leave of speech implor'd, And humble deprecation thus repli'd. Let not my words offend thee, Heav'nly Power, My Maker, be propitious while I speak. Hast thou not made me here thy substitute, And these inferiour farr beneath me set? Among unequals what societie Can sort, what harmonie or true delight? Which must be mutual, in proportion due Giv'n and receiv'd; but in disparitie The one intense, the other still remiss Cannot well suite with either, but soon prove Tedious alike: Of fellowship I speak Such as I seek, fit to participate All rational delight, wherein the brute Cannot be human consort; they rejoyce Each with thir kinde, Lion with Lioness; So fitly them in pairs thou hast combin'd; Much less can Bird with Beast, or Fish with Fowle So well converse, nor with the Ox the Ape; Wors then can Man with Beast, and least of all. Whereto th' Almighty answer'd, not displeas'd. A nice and suttle happiness I see Thou to thy self proposest, in the choice Of thy Associates, ADAM, and wilt taste No pleasure, though in pleasure, solitarie. What thinkst thou then of mee, and this my State, Seem I to thee sufficiently possest Of happiness, or not? who am alone From all Eternitie, for none I know Second to mee or like, equal much less. How have I then with whom to hold converse Save with the Creatures which I made, and those To me inferiour, infinite descents Beneath what other Creatures are to thee? He ceas'd, I lowly answer'd. To attaine The highth and depth of thy Eternal wayes All human thoughts come short, Supream of things; Thou in thy self art perfet, and in thee Is no deficience found; not so is Man, But in degree, the cause of his desire By conversation with his like to help, Or solace his defects. No need that thou Shouldst propagat, already infinite; And through all numbers absolute, though One; But Man by number is to manifest His single imperfection, and beget Like of his like, his Image multipli'd, In unitie defective, which requires Collateral love, and deerest amitie. Thou in thy secresie although alone, Best with thy self accompanied, seek'st not Social communication, yet so pleas'd, Canst raise thy Creature to what highth thou wilt Of Union or Communion, deifi'd; I by conversing cannot these erect From prone, nor in thir wayes complacence find. Thus I embold'nd spake, and freedom us'd Permissive, and acceptance found, which gain'd This answer from the gratious voice Divine. Thus farr to try thee, ADAM, I was pleas'd, And finde thee knowing not of Beasts alone, Which thou hast rightly nam'd, but of thy self, Expressing well the spirit within thee free, My Image, not imparted to the Brute, Whose fellowship therefore unmeet for thee Good reason was thou freely shouldst dislike, And be so minded still; I, ere thou spak'st, Knew it not good for Man to be alone, And no such companie as then thou saw'st Intended thee, for trial onely brought, To see how thou could'st judge of fit and meet: What next I bring shall please thee, be assur'd, Thy likeness, thy fit help, thy other self, Thy wish, exactly to thy hearts desire. Hee ended, or I heard no more, for now My earthly by his Heav'nly overpowerd, Which it had long stood under, streind to the highth In that celestial Colloquie sublime, As with an object that excels the sense, Dazl'd and spent, sunk down, and sought repair Of sleep, which instantly fell on me, call'd By Nature as in aide, and clos'd mine eyes. Mine eyes he clos'd, but op'n left the Cell Of Fancie my internal sight, by which Abstract as in a transe methought I saw, Though sleeping, where I lay, and saw the shape Still glorious before whom awake I stood; Who stooping op'nd my left side, and took From thence a Rib, with cordial spirits warme, And Life-blood streaming fresh; wide was the wound, But suddenly with flesh fill'd up & heal'd: The Rib he formd and fashond with his hands; Under his forming hands a Creature grew, Manlike, but different sex, so lovly faire, That what seemd fair in all the World, seemd now Mean, or in her summd up, in her containd And in her looks, which from that time infus'd Sweetness into my heart, unfelt before, And into all things from her Aire inspir'd The spirit of love and amorous delight. She disappeerd, and left me dark, I wak'd To find her, or for ever to deplore Her loss, and other pleasures all abjure: When out of hope, behold her, not farr off, Such as I saw her in my dream, adornd With what all Earth or Heaven could bestow To make her amiable: On she came, Led by her Heav'nly Maker, though unseen, And guided by his voice, nor uninformd Of nuptial Sanctitie and marriage Rites: Grace was in all her steps, Heav'n in her Eye, In every gesture dignitie and love. I overjoyd could not forbear aloud. This turn hath made amends; thou hast fulfill'd Thy words, Creator bounteous and benigne, Giver of all things faire, but fairest this Of all thy gifts, nor enviest. I now see Bone of my Bone, Flesh of my Flesh, my Self Before me; Woman is her Name, of Man Extracted; for this cause he shall forgoe Father and Mother, and to his Wife adhere; And they shall be one Flesh, one Heart, one Soule. She heard me thus, and though divinely brought, Yet Innocence and Virgin Modestie, Her vertue and the conscience of her worth, That would be woo'd, and not unsought be won, Not obvious, not obtrusive, but retir'd, The more desirable, or to say all, Nature her self, though pure of sinful thought, Wrought in her so, that seeing me, she turn'd; I follow'd her, she what was Honour knew, And with obsequious Majestie approv'd My pleaded reason. To the Nuptial Bowre I led her blushing like the Morn: all Heav'n, And happie Constellations on that houre Shed thir selectest influence; the Earth Gave sign of gratulation, and each Hill; Joyous the Birds; fresh Gales and gentle Aires Whisper'd it to the Woods, and from thir wings Flung Rose, flung Odours from the spicie Shrub, Disporting, till the amorous Bird of Night Sung Spousal, and bid haste the Eevning Starr On his Hill top, to light the bridal Lamp. Thus I have told thee all my State, and brought My Storie to the sum of earthly bliss Which I enjoy, and must confess to find In all things else delight indeed, but such As us'd or not, works in the mind no change, Nor vehement desire, these delicacies I mean of Taste, Sight, Smell, Herbs, Fruits, & Flours, Walks, and the melodie of Birds; but here Farr otherwise, transported I behold, Transported touch; here passion first I felt, Commotion strange, in all enjoyments else Superiour and unmov'd, here onely weake Against the charm of Beauties powerful glance. Or Nature faild in mee, and left some part Not proof enough such Object to sustain, Or from my side subducting, took perhaps More then enough; at least on her bestow'd Too much of Ornament, in outward shew Elaborate, of inward less exact. For well I understand in the prime end Of Nature her th' inferiour, in the mind And inward Faculties, which most excell, In outward also her resembling less His Image who made both, and less expressing The character of that Dominion giv'n O're other Creatures; yet when I approach Her loveliness, so absolute she seems And in her self compleat, so well to know Her own, that what she wills to do or say, Seems wisest, vertuousest, discreetest, best; All higher knowledge in her presence falls Degraded, Wisdom in discourse with her Looses discount'nanc't, and like folly shewes; Authoritie and Reason on her waite, As one intended first, not after made Occasionally; and to consummate all, Greatness of mind and nobleness thir seat Build in her loveliest, and create an awe About her, as a guard Angelic plac't. To whom the Angel with contracted brow. Accuse not Nature, she hath don her part; Do thou but thine, and be not diffident Of Wisdom, she deserts thee not, if thou Dismiss not her, when most thou needst her nigh, By attributing overmuch to things Less excellent, as thou thy self perceav'st. For what admir'st thou, what transports thee so, An outside? fair no doubt, and worthy well Thy cherishing, thy honouring, and thy love, Not thy subjection: weigh with her thy self; Then value: Oft times nothing profits more Then self-esteem, grounded on just and right Well manag'd; of that skill the more thou know'st, The more she will acknowledge thee her Head, And to realities yeild all her shows; Made so adorn for thy delight the more, So awful, that with honour thou maist love Thy mate, who sees when thou art seen least wise. But if the sense of touch whereby mankind Is propagated seem such dear delight Beyond all other, think the same voutsaf't To Cattel and each Beast; which would not be To them made common & divulg'd, if aught Therein enjoy'd were worthy to subdue The Soule of Man, or passion in him move. What higher in her societie thou findst Attractive, human, rational, love still; In loving thou dost well, in passion not, Wherein true Love consists not; love refines The thoughts, and heart enlarges, hath his seat In Reason, and is judicious, is the scale By which to heav'nly Love thou maist ascend, Not sunk in carnal pleasure, for which cause Among the Beasts no Mate for thee was found. To whom thus half abash't ADAM repli'd. Neither her out-side formd so fair, nor aught In procreation common to all kindes (Though higher of the genial Bed by far, And with mysterious reverence I deem) So much delights me, as those graceful acts, Those thousand decencies that daily flow From all her words and actions, mixt with Love And sweet compliance, which declare unfeign'd Union of Mind, or in us both one Soule; Harmonie to behold in wedded pair More grateful then harmonious sound to the eare. Yet these subject not; I to thee disclose What inward thence I feel, not therefore foild, Who meet with various objects, from the sense Variously representing; yet still free Approve the best, and follow what I approve. To love thou blam'st me not, for love thou saist Leads up to Heav'n, is both the way and guide; Bear with me then, if lawful what I ask; Love not the heav'nly Spirits, and how thir Love Express they, by looks onely, or do they mix Irradiance, virtual or immediate touch? To whom the Angel with a smile that glow'd Celestial rosie red, Loves proper hue, Answer'd. Let it suffice thee that thou know'st Us happie, and without Love no happiness. Whatever pure thou in the body enjoy'st (And pure thou wert created) we enjoy In eminence, and obstacle find none Of membrane, joynt, or limb, exclusive barrs: Easier then Air with Air, if Spirits embrace, Total they mix, Union of Pure with Pure Desiring; nor restrain'd conveyance need As Flesh to mix with Flesh, or Soul with Soul. But I can now no more; the parting Sun Beyond the Earths green Cape and verdant Isles HESPEREAN sets, my Signal to depart. Be strong, live happie, and love, but first of all Him whom to love is to obey, and keep His great command; take heed least Passion sway Thy Judgement to do aught, which else free Will Would not admit; thine and of all thy Sons The weal or woe in thee is plac't; beware. I in thy persevering shall rejoyce, And all the Blest: stand fast; to stand or fall Free in thine own Arbitrement it lies. Perfet within, no outward aid require; And all temptation to transgress repel. So saying, he arose; whom ADAM thus Follow'd with benediction. Since to part, Go heavenly Guest, Ethereal Messenger, Sent from whose sovran goodness I adore. Gentle to me and affable hath been Thy condescension, and shall be honour'd ever With grateful Memorie: thou to mankind Be good and friendly still, and oft return. So parted they, the Angel up to Heav'n From the thick shade, and ADAM to his Bowre. THE END OF THE SEVENTH BOOK. PARADISE LOST BOOK VIII. No more of talk where God or Angel Guest With Man, as with his Friend, familiar us'd To sit indulgent, and with him partake Rural repast, permitting him the while Venial discourse unblam'd: I now must change Those Notes to Tragic; foul distrust, and breach Disloyal on the part of Man, revolt And disobedience: On the part of Heav'n Now alienated, distance and distaste, Anger and just rebuke, and judgement giv'n, That brought into this World a world of woe, Sinne and her shadow Death, and Miserie Deaths Harbinger: Sad task, yet argument Not less but more Heroic then the wrauth Of stern ACHILLES on his Foe pursu'd Thrice Fugitive about TROY Wall; or rage Of TURNUS for LAVINIA disespous'd, Or NEPTUN'S ire or JUNO'S, that so long Perplex'd the GREEK and CYTHEREA'S Son; If answerable style I can obtaine Of my Celestial Patroness, who deignes Her nightly visitation unimplor'd, And dictates to me slumbring, or inspires Easie my unpremeditated Verse: Since first this subject for Heroic Song Pleas'd me long choosing, and beginning late; Not sedulous by Nature to indite Warrs, hitherto the onely Argument Heroic deem'd, chief maistrie to dissect With long and tedious havoc fabl'd Knights In Battels feign'd; the better fortitude Of Patience and Heroic Martyrdom Unsung; or to describe Races and Games, Or tilting Furniture, emblazon'd Shields, Impreses quaint, Caparisons and Steeds; Bases and tinsel Trappings, gorgious Knights At Joust and Torneament; then marshal'd Feast Serv'd up in Hall with Sewers, and Seneshals; The skill of Artifice or Office mean, Not that which justly gives Heroic name To Person or to Poem. Mee of these Nor skilld nor studious, higher Argument Remaines, sufficient of it self to raise That name, unless an age too late, or cold Climat, or Years damp my intended wing Deprest, and much they may, if all be mine, Not Hers who brings it nightly to my Ear. The Sun was sunk, and after him the Starr Of HESPERUS, whose Office is to bring Twilight upon the Earth, short Arbiter Twixt Day and Night, and now from end to end Nights Hemisphere had veild the Horizon round: When SATAN who late fled before the threats Of GABRIEL out of EDEN, now improv'd In meditated fraud and malice, bent On mans destruction, maugre what might hap Of heavier on himself, fearless return'd. By Night he fled, and at Midnight return'd From compassing the Earth, cautious of day, Since URIEL Regent of the Sun descri'd His entrance, and forewarnd the Cherubim That kept thir watch; thence full of anguish driv'n, The space of seven continu'd Nights he rode With darkness, thrice the Equinoctial Line He circl'd, four times cross'd the Carr of Night From Pole to Pole, traversing each Colure; On the eighth return'd, and on the Coast averse From entrance or Cherubic Watch, by stealth Found unsuspected way. There was a place, Now not, though Sin, not Time, first wraught the change, Where TIGRIS at the foot of Paradise Into a Gulf shot under ground, till part Rose up a Fountain by the Tree of Life; In with the River sunk, and with it rose Satan involv'd in rising Mist, then sought Where to lie hid; Sea he had searcht and Land From EDEN over PONTUS, and the Poole MAEOTIS, up beyond the River OB; Downward as farr Antartic; and in length West from ORANTES to the Ocean barr'd At DARIEN, thence to the Land where flowes GANGES and INDUS: thus the Orb he roam'd With narrow search; and with inspection deep Consider'd every Creature, which of all Most opportune might serve his Wiles, and found The Serpent suttlest Beast of all the Field. Him after long debate, irresolute Of thoughts revolv'd, his final sentence chose Fit Vessel, fittest Imp of fraud, in whom To enter, and his dark suggestions hide From sharpest sight: for in the wilie Snake, Whatever sleights none would suspicious mark, As from his wit and native suttletie Proceeding, which in other Beasts observ'd Doubt might beget of Diabolic pow'r Active within beyond the sense of brute. Thus he resolv'd, but first from inward griefe His bursting passion into plaints thus pour'd: O Earth, how like to Heav'n, if not preferrd More justly, Seat worthier of Gods, as built With second thoughts, reforming what was old! For what God after better worse would build? Terrestrial Heav'n, danc't round by other Heav'ns That shine, yet bear thir bright officious Lamps, Light above Light, for thee alone, as seems, In thee concentring all thir precious beams Of sacred influence: As God in Heav'n Is Center, yet extends to all, so thou Centring receav'st from all those Orbs; in thee, Not in themselves, all thir known vertue appeers Productive in Herb, Plant, and nobler birth Of Creatures animate with gradual life Of Growth, Sense, Reason, all summ'd up in Man. With what delight could I have walkt thee round If I could joy in aught, sweet interchange Of Hill and Vallie, Rivers, Woods and Plaines, Now Land, now Sea, & Shores with Forrest crownd, Rocks, Dens, and Caves; but I in none of these Find place or refuge; and the more I see Pleasures about me, so much more I feel Torment within me, as from the hateful siege Of contraries; all good to me becomes Bane, and in Heav'n much worse would be my state. But neither here seek I, no nor in Heav'n To dwell, unless by maistring Heav'ns Supreame; Nor hope to be my self less miserable By what I seek, but others to make such As I though thereby worse to me redound: For onely in destroying I finde ease To my relentless thoughts; and him destroyd, Or won to what may work his utter loss, For whom all this was made, all this will soon Follow, as to him linkt in weal or woe, In wo then; that destruction wide may range: To mee shall be the glorie sole among The infernal Powers, in one day to have marr'd What he ALMIGHTIE styl'd, six Nights and Days Continu'd making, and who knows how long Before had bin contriving, though perhaps Not longer then since I in one Night freed From servitude inglorious welnigh half Th' Angelic Name, and thinner left the throng Of his adorers: hee to be aveng'd, And to repaire his numbers thus impair'd, Whether such vertue spent of old now faild More Angels to Create, if they at least Are his Created or to spite us more, Determin'd to advance into our room A Creature form'd of Earth, and him endow, Exalted from so base original, With Heav'nly spoils, our spoils: What he decreed He effected; Man he made, and for him built Magnificent this World, and Earth his seat, Him Lord pronounc'd, and, O indignitie! Subjected to his service Angel wings, And flaming Ministers to watch and tend Thir earthlie Charge: Of these the vigilance I dread, and to elude, thus wrapt in mist Of midnight vapor glide obscure, and prie In every Bush and Brake, where hap may finde The Serpent sleeping, in whose mazie foulds To hide me, and the dark intent I bring. O foul descent! that I who erst contended With Gods to sit the highest, am now constraind Into a Beast, and mixt with bestial slime, This essence to incarnate and imbrute, That to the hight of Deitie aspir'd; But what will not Ambition and Revenge Descend to? who aspires must down as low As high he soard, obnoxious first or last To basest things. Revenge, at first though sweet, Bitter ere long back on it self recoiles; Let it; I reck not, so it light well aim'd, Since higher I fall short, on him who next Provokes my envie, this new Favorite Of Heav'n, this Man of Clay, Son of despite, Whom us the more to spite his Maker rais'd From dust: spite then with spite is best repaid. So saying, through each Thicket Danck or Drie, Like a black mist low creeping, he held on His midnight search, where soonest he might finde The Serpent: him fast sleeping soon he found In Labyrinth of many a round self-rowl'd, His head the midst, well stor'd with suttle wiles: Not yet in horrid Shade or dismal Den, Not nocent yet, but on the grassie Herbe Fearless unfeard he slept: in at his Mouth The Devil enterd, and his brutal sense, In heart or head, possessing soon inspir'd With act intelligential; but his sleep Disturbd not, waiting close th' approach of Morn. Now whenas sacred Light began to dawne In EDEN on the humid Flours, that breathd Thir morning Incense, when all things that breath, From th' Earths great Altar send up silent praise To the Creator, and his Nostrils fill With gratefull Smell, forth came the human pair And joynd thir vocal Worship to the Quire Of Creatures wanting voice, that done, partake The season, prime for sweetest Sents and Aires: Then commune how that day they best may ply Thir growing work: for much thir work outgrew The hands dispatch of two Gardning so wide. And EVE first to her Husband thus began. ADAM, well may we labour still to dress This Garden, still to tend Plant, Herb and Flour. Our pleasant task enjoyn'd, but till more hands Aid us, the work under our labour grows, Luxurious by restraint; what we by day Lop overgrown, or prune, or prop, or bind, One night or two with wanton growth derides Tending to wilde. Thou therefore now advise Or hear what to my mind first thoughts present, Let us divide our labours, thou where choice Leads thee, or where most needs, whether to wind The Woodbine round this Arbour, or direct The clasping Ivie where to climb, while I In yonder Spring of Roses intermixt With Myrtle, find what to redress till Noon: For while so near each other thus all day Our task we choose, what wonder if no near Looks intervene and smiles, or object new Casual discourse draw on, which intermits Our dayes work brought to little, though begun Early, and th' hour of Supper comes unearn'd. To whom mild answer ADAM thus return'd. Sole EVE, Associate sole, to me beyond Compare above all living Creatures deare, Well hast thou motion'd, wel thy thoughts imployd How we might best fulfill the work which here God hath assign'd us, nor of me shalt pass Unprais'd: for nothing lovelier can be found In woman, then to studie houshold good, And good workes in her Husband to promote. Yet not so strictly hath our Lord impos'd Labour, as to debarr us when we need Refreshment, whether food, or talk between, Food of the mind, or this sweet intercourse Of looks and smiles, for smiles from Reason flow, To brute deni'd, and are of Love the food, Love not the lowest end of human life. For not to irksom toile, but to delight He made us, and delight to Reason joyn'd. These paths and Bowers doubt not but our joynt Will keep from Wilderness with ease, as wide As we need walk, till younger hands ere long Assist us: But if much converse perhaps Thee satiate, to short absence I could yeild. For solitude somtimes is best societie, And short retirement urges sweet returne. But other doubt possesses me, least harm Befall thee sever'd from me; for thou knowst What hath bin warn'd us, what malicious Foe Envying our happiness, and of his own Despairing, seeks to work us woe and shame By sly assault; and somwhere nigh at hand Watches, no doubt, with greedy hope to find His wish and best advantage, us asunder, Hopeless to circumvent us joynd, where each To other speedie aide might lend at need; Whether his first design be to withdraw Our fealtie from God, or to disturb Conjugal Love, then which perhaps no bliss Enjoy'd by us excites his envie more; Or this, or worse, leave not the faithful side That gave thee being, stil shades thee and protects. The Wife, where danger or dishonour lurks, Safest and seemliest by her Husband staies, Who guards her, or with her the worst endures. To whom the Virgin Majestie of EVE, As one who loves, and some unkindness meets, With sweet austeer composure thus reply'd. Ofspring of Heav'n and Earth, and all Earths Lord, That such an enemie we have, who seeks Our ruin, both by thee informd I learne, And from the parting Angel over-heard As in a shadie nook I stood behind, Just then returnd at shut of Evening Flours. But that thou shouldst my firmness therefore doubt To God or thee, because we have a foe May tempt it, I expected not to hear. His violence thou fearst not, being such, As wee, not capable of death or paine, Can either not receave, or can repell. His fraud is then thy fear, which plain inferrs Thy equal fear that my firm Faith and Love Can by his fraud be shak'n or seduc't; Thoughts, which how found they harbour in thy Brest, ADAM, misthought of her to thee so dear? To whom with healing words ADAM reply'd. Daughter of God and Man, immortal EVE, For such thou art, from sin and blame entire: Not diffident of thee do I dissuade Thy absence from my sight, but to avoid Th' attempt it self, intended by our Foe. For hee who tempts, though in vain, at least asperses The tempted with dishonour foul, suppos'd Not incorruptible of Faith, not prooff Against temptation: thou thy self with scorne And anger wouldst resent the offer'd wrong, Though ineffectual found: misdeem not then, If such affront I labour to avert From thee alone, which on us both at once The Enemie, though bold, will hardly dare, Or daring, first on mee th' assault shall light. Nor thou his malice and false guile contemn; Suttle he needs must be, who could seduce Angels, nor think superfluous others aid. I from the influence of thy looks receave Access in every Vertue, in thy sight More wise, more watchful, stronger, if need were Of outward strength; while shame, thou looking on, Shame to be overcome or over-reacht Would utmost vigor raise, and rais'd unite. Why shouldst not thou like sense within thee feel When I am present, and thy trial choose With me, best witness of thy Vertue tri'd. So spake domestick ADAM in his care And Matrimonial Love, but EVE, who thought Less attributed to her Faith sincere, Thus her reply with accent sweet renewd. If this be our condition, thus to dwell In narrow circuit strait'nd by a Foe, Suttle or violent, we not endu'd Single with like defence, wherever met, How are we happie, still in fear of harm? But harm precedes not sin: onely our Foe Tempting affronts us with his foul esteem Of our integritie: his foul esteeme Sticks no dishonor on our Front, but turns Foul on himself; then wherfore shund or feard By us? who rather double honour gaine From his surmise prov'd false, finde peace within, Favour from Heav'n, our witness from th' event. And what is Faith, Love, Vertue unassaid Alone, without exterior help sustaind? Let us not then suspect our happie State Left so imperfet by the Maker wise, As not secure to single or combin'd. Fraile is our happiness, if this be so, And EDEN were no EDEN thus expos'd. To whom thus ADAM fervently repli'd. O Woman, best are all things as the will Of God ordaind them, his creating hand Nothing imperfet or deficient left Of all that he Created, much less Man, Or ought that might his happie State secure, Secure from outward force; within himself The danger lies, yet lies within his power: Against his will he can receave no harme. But God left free the Will, for what obeyes Reason, is free, and Reason he made right, But bid her well beware, and still erect, Least by some faire appeering good surpris'd She dictate false, and missinforme the Will To do what God expresly hath forbid. Not then mistrust, but tender love enjoynes, That I should mind thee oft, and mind thou me. Firm we subsist, yet possible to swerve, Since Reason not impossibly may meet Some specious object by the Foe subornd, And fall into deception unaware, Not keeping strictest watch, as she was warnd. Seek not temptation then, which to avoide Were better, and most likelie if from mee Thou sever not; Trial will come unsought. Wouldst thou approve thy constancie, approve First thy obedience; th' other who can know, Not seeing thee attempted, who attest? But if thou think, trial unsought may finde Us both securer then thus warnd thou seemst, Go; for thy stay, not free, absents thee more; Go in thy native innocence, relie On what thou hast of vertue, summon all, For God towards thee hath done his part, do thine. So spake the Patriarch of Mankinde, but EVE Persisted, yet submiss, though last, repli'd. With thy permission then, and thus forewarnd Chiefly by what thy own last reasoning words Touchd onely, that our trial, when least sought, May finde us both perhaps farr less prepar'd, The willinger I goe, nor much expect A Foe so proud will first the weaker seek; So bent, the more shall shame him his repulse. Thus saying, from her Husbands hand her hand Soft she withdrew, and like a Wood-Nymph light OREAD or DRYAD, or of DELIA's Traine, Betook her to the Groves, but DELIA's self In gate surpass'd and Goddess-like deport, Though not as shee with Bow and Quiver armd, But with such Gardning Tools as Are yet rude, Guiltless of fire had formd, or Angels brought, To PALES, or POMONA, thus adornd, Likest she seemd, POMONA when she fled VERTUMNUS, or to CERES in her Prime, Yet Virgin of PROSERPINA from JOVE. Her long with ardent look his EYE pursu'd Delighted, but desiring more her stay. Oft he to her his charge of quick returne, Repeated, shee to him as oft engag'd To be returnd by Noon amid the Bowre, And all things in best order to invite Noontide repast, or Afternoons repose. O much deceav'd, much failing, hapless EVE, Of thy presum'd return! event perverse! Thou never from that houre in Paradise Foundst either sweet repast, or found repose; Such ambush hid among sweet Flours and Shades Waited with hellish rancor imminent To intercept thy way, or send thee back Despoild of Innocence, of Faith, of Bliss. For now, and since first break of dawne the Fiend, Meer Serpent in appearance, forth was come, And on his Quest, where likeliest he might finde The onely two of Mankinde, but in them The whole included Race, his purposd prey. In Bowre and Field he sought, where any tuft Of Grove or Garden-Plot more pleasant lay, Thir tendance or Plantation for delight, By Fountain or by shadie Rivulet He sought them both, but wish'd his hap might find EVE separate, he wish'd, but not with hope Of what so seldom chanc'd, when to his wish, Beyond his hope, EVE separate he spies, Veild in a Cloud of Fragrance, where she stood, Half spi'd, so thick the Roses bushing round About her glowd, oft stooping to support Each Flour of slender stalk, whose head though gay Carnation, Purple, Azure, or spect with Gold, Hung drooping unsustaind, them she upstaies Gently with Mirtle band, mindless the while, Her self, though fairest unsupported Flour, From her best prop so farr, and storn so nigh. Neererhe drew, and many a walk travers'd Of stateliest Covert, Cedar, Pine, or Palme, Then voluble and bold, now hid, now seen Among thick-wov'n Arborets and Flours Imborderd on each Bank, the hand of EVE: Spot more delicious then those Gardens feign'd Or of reviv'd ADONIS, or renownd ALCINOUS, host of old LAERTES Son, Or that, not Mystic, where the Sapient King Held dalliance with his faire EGYPTIAN Spouse. Much hee the Place admir'd, the Person more. As one who long in populous City pent, Where Houses thick and Sewers annoy the Aire, Forth issuing on a Summers Morn, to breathe Among the pleasant Villages and Farmes Adjoynd, from each thing met conceaves delight, The smell of Grain, or tedded Grass, or Kine, Or Dairie, each rural sight, each rural sound; If chance with Nymphlike step fair Virgin pass, What pleasing seemd, for her now pleases more, She most, and in her look summs all Delight. Such Pleasure took the Serpent to behold This Flourie Plat, the sweet recess of EVE Thus earlie, thus alone; her Heav'nly forme Angelic, but more soft, and Feminine, Her graceful Innocence, her every Aire Of gesture or lest action overawd His Malice, and with rapine sweet bereav'd His fierceness of the fierce intent it brought: That space the Evil one abstracted stood From his own evil, and for the time remaind Stupidly good, of enmitie disarm'd, Of guile, of hate, of envie, of revenge; But the hot Hell that alwayes in him burnes, Though in mid Heav'n, soon ended his delight, And tortures him now more, the more he sees Of pleasure not for him ordain'd: then soon Fierce hate he recollects, and all his thoughts Of mischief, gratulating, thus excites. Thoughts, whither have he led me, with what sweet Compulsion thus transported to forget What hither brought us, hate, not love, nor hope Of Paradise for Hell, hope here to taste Of pleasure, but all pleasure to destroy, Save what is in destroying, other joy To me is lost. Then let me not let pass Occasion which now smiles, behold alone The Woman, opportune to all attempts, Her Husband, for I view far round, not nigh, Whose higher intellectual more I shun, And strength, of courage hautie, and of limb Heroic built, though of terrestrial mould, Foe not informidable, exempt from wound, I not; so much hath Hell debas'd, and paine Infeebl'd me, to what I was in Heav'n. Shee fair, divinely fair, fit Love for Gods, Not terrible, though terrour be in Love And beautie, not approacht by stronger hate, Hate stronger, under shew of Love well feign'd, The way which to her ruin now I tend. So spake the Enemie of Mankind, enclos'd In Serpent, Inmate bad, and toward EVE Address'd his way, not with indented wave, Prone on the ground, as since, but on his reare, Circular base of rising foulds, that tour'd Fould above fould a surging Maze, his Head Crested aloft, and Carbuncle his Eyes; With burnisht Neck of verdant Gold, erect Amidst his circling Spires, that on the grass Floted redundant: pleasing was his shape, And lovely, never since of Serpent kind Lovelier, not those that in ILLYRIA chang'd HERMIONE and CADMUS, or the God In EPIDAURUS; nor to which transformd AMMONIAN JOVE, or CAPITOLINE was seen, Hee with OLYMPIAS, this with her who bore SCIPIO the highth of ROME. With tract oblique At first, as one who sought access, but feard To interrupt, side-long he works his way. As when a Ship by skilful Stearsman wrought Nigh Rivers mouth or Foreland, where the Wind Veres oft, as oft so steers, and shifts her Saile; So varied hee, and of his tortuous Traine Curld many a wanton wreath in sight of EVE, To lure her Eye; shee busied heard the sound Of rusling Leaves, but minded not, as us'd To such disport before her through the Field, From every Beast, more duteous at her call, Then at CIRCEAN call the Herd disguis'd. Hee boulder now, uncall'd before her stood; But as in gaze admiring: Oft he bowd His turret Crest, and sleek enamel'd Neck, Fawning, and lick'd the ground whereon she trod. His gentle dumb expression turnd at length The Eye of EVE to mark his play; he glad Of her attention gaind, with Serpent Tongue Organic, or impulse of vocal Air, His fraudulent temptation thus began. Wonder not, sovran Mistress, if perhaps Thou canst, who art sole Wonder, much less arm Thy looks, the Heav'n of mildness, with disdain, Displeas'd that I approach thee thus, and gaze Insatiate, I thus single; nor have feard Thy awful brow, more awful thus retir'd. Fairest resemblance of thy Maker faire, Thee all living things gaze on, all things thine By gift, and thy Celestial Beautie adore With ravishment beheld, there best beheld Where universally admir'd; but here In this enclosure wild, these Beasts among, Beholders rude, and shallow to discerne Half what in thee is fair, one man except, Who sees thee? (and what is one?) who shouldst be seen A Goddess among Gods, ador'd and serv'd By Angels numberless, thy daily Train. So gloz'd the Tempter, and his Proem tun'd; Into the Heart of EVE his words made way, Though at the voice much marveling; at length Not unamaz'd she thus in answer spake. What may this mean? Language of Man pronounc't By Tongue of Brute, and human sense exprest? The first at lest of these I thought deni'd To Beasts, whom God on their Creation-Day Created mute to all articulat sound; The latter I demurre, for in thir looks Much reason, and in thir actions oft appeers. Thee, Serpent, suttlest beast of all the field I knew, but not with human voice endu'd; Redouble then this miracle, and say, How cam'st thou speakable of mute, and how To me so friendly grown above the rest Of brutal kind, that daily are in sight? Say, for such wonder claims attention due. To whom the guileful Tempter thus reply'd. Empress of this fair World, resplendent EVE, Easie to mee it is to tell thee all What thou commandst, and right thou shouldst be obeyd: I was at first as other Beasts that graze The trodden Herb, of abject thoughts and low, As was my food, nor aught but food discern'd Or Sex, and apprehended nothing high: Till on a day roaving the field, I chanc'd A goodly Tree farr distant to behold Loaden with fruit of fairest colours mixt, Ruddie and Gold: I nearer drew to gaze; When from the boughes a savorie odour blow'n, Grateful to appetite, more pleas'd my sense Then smell of sweetest Fenel, or the Teats Of Ewe or Goat dropping with Milk at Eevn, Unsuckt of Lamb or Kid, that tend thir play. To satisfie the sharp desire I had Of tasting those fair Apples, I resolv'd Not to deferr; hunger and thirst at once, Powerful perswaders, quick'nd at the scent Of that alluring fruit, urg'd me so keene. About the Mossie Trunk I wound me soon, For high from ground the branches would require Thy utmost reach or ADAMS: Round the Tree All other Beasts that saw, with like desire Longing and envying stood, but could not reach. Amid the Tree now got, where plentie hung Tempting so nigh, to pluck and eat my fill I spar'd not, for such pleasure till that hour At Feed or Fountain never had I found. Sated at length, ere long I might perceave Strange alteration in me, to degree Of Reason in my inward Powers, and Speech Wanted not long, though to this shape retaind. Thenceforth to Speculations high or deep I turnd my thoughts, and with capacious mind Considerd all things visible in Heav'n, Or Earth, or Middle, all things fair and good; But all that fair and good in thy Divine Semblance, and in thy Beauties heav'nly Ray United I beheld; no Fair to thine Equivalent or second, which compel'd Mee thus, though importune perhaps, to come And gaze, and worship thee of right declar'd Sovran of Creatures, universal Dame. So talk'd the spirited sly Snake; and EVE Yet more amaz'd unwarie thus reply'd. Serpent, thy overpraising leaves in doubt The vertue of that Fruit, in thee first prov'd: But say, where grows the Tree, from hence how far? For many are the Trees of God that grow In Paradise, and various, yet unknown To us, in such abundance lies our choice, As leaves a greater store of Fruit untoucht, Still hanging incorruptible, till men Grow up to thir provision, and more hands Help to disburden Nature of her Bearth. To whom the wilie Adder, blithe and glad. Empress, the way is readie, and not long, Beyond a row of Myrtles, on a Flat, Fast by a Fountain, one small Thicket past Of blowing Myrrh and Balme; if thou accept My conduct, I can bring thee thither soon. Lead then, said EVE. Hee leading swiftly rowld In tangles, and make intricate seem strait, To mischief swift. Hope elevates, and joy Bright'ns his Crest, as when a wandring Fire Compact of unctuous vapor, which the Night Condenses, and the cold invirons round, Kindl'd through agitation to a Flame, Which oft, they say, some evil Spirit attends, Hovering and blazing with delusive Light, Misleads th' amaz'd Night-wanderer from his way To Boggs and Mires, & oft through Pond or Poole, There swallow'd up and lost, from succour farr. So glister'd the dire Snake and into fraud Led EVE our credulous Mother, to the Tree Of prohibition, root of all our woe; Which when she saw, thus to her guide she spake. Serpent, we might have spar'd our coming hither, Fruitless to me, though Fruit be here to excess, The credit of whose vertue rest with thee, Wondrous indeed, if cause of such effects. But of this Tree we may not taste nor touch; God so commanded, and left that Command Sole Daughter of his voice; the rest, we live Law to our selves, our Reason is our Law. To whom the Tempter guilefully repli'd. Indeed? hath God then said that of the Fruit Of all these Garden Trees ye shall not eate, Yet Lords declar'd of all in Earth or Aire? To whom thus EVE yet sinless. Of the Fruit Of each Tree in the Garden we may eate, But of the Fruit of this fair Tree amidst The Garden, God hath said, Ye shall not eate Thereof, nor shall ye touch it, least ye die. She scarse had said, though brief, when now more bold The Tempter, but with shew of Zeale and Love To Man, and indignation at his wrong, New part puts on, and as to passion mov'd, Fluctuats disturbd, yet comely, and in act Rais'd, as of som great matter to begin. As when of old som Orator renound In ATHENS or free ROME, where Eloquence Flourishd, since mute, to som great cause addrest, Stood in himself collected, while each part, Motion, each act won audience ere the tongue, Somtimes in highth began, as no delay Of Preface brooking through his Zeal of Right. So standing, moving, or to highth upgrown The Tempter all impassiond thus began. O Sacred, Wise, and Wisdom-giving Plant, Mother of Science, Now I feel thy Power Within me cleere, not onely to discerne Things in thir Causes, but to trace the wayes Of highest Agents, deemd however wise. Queen of this Universe, doe not believe Those rigid threats of Death; ye shall not Die: How should ye? by the Fruit? it gives you Life To Knowledge? By the Threatner, look on mee, Mee who have touch'd and tasted, yet both live, And life more perfet have attaind then Fate Meant mee, by ventring higher then my Lot. Shall that be shut to Man, which to the Beast Is open? or will God incense his ire For such a pretty Trespass, and not praise Rather your dauntless vertue, whom the pain Of Death denounc't, whatever thing Death be, Deterrd not from atchieving what might leade To happier life, knowledge of Good and Evil; Of good, how just? of evil, if what is evil Be real, why not known, since easier shunnd? God therefore cannot hurt ye, and be just; Not just, not God; not feard then, nor obeid: Your feare it self of Death removes the feare. Why then was this forbid? Why but to awe, Why but to keep ye low and ignorant, His worshippers; he knows that in the day Ye Eate thereof, your Eyes that seem so cleere, Yet are but dim, shall perfetly be then Op'nd and cleerd, and ye shall be as Gods, Knowing both Good and Evil as they know. That ye should be as Gods, since I as Man, Internal Man, is but proportion meet, I of brute human, yee of human Gods. So ye shalt die perhaps, by putting off Human, to put on Gods, death to be wisht, Though threat'nd, which no worse then this can bring And what are Gods that Man may not become As they, participating God-like food? The Gods are first, and that advantage use On our belief, that all from them proceeds, I question it, for this fair Earth I see, Warm'd by the Sun, producing every kind, Them nothing: If they all things, who enclos'd Knowledge of Good and Evil in this Tree, That whoso eats thereof, forthwith attains Wisdom without their leave? and wherein lies Th' offence, that Man should thus attain to know? What can your knowledge hurt him, or this Tree Impart against his will if all be his? Or is it envie, and can envie dwell In heav'nly brests? these, these and many more Causes import your need of this fair Fruit. Goddess humane, reach then, and freely taste. He ended, and his words replete with guile Into her heart too easie entrance won: Fixt on the Fruit she gaz'd, which to behold Might tempt alone, and in her ears the sound Yet rung of his perswasive words, impregn'd With Reason, to her seeming, and with Truth; Meanwhile the hour of Noon drew on, and wak'd An eager appetite, rais'd by the smell So savorie of that Fruit, which with desire, Inclinable now grown to touch or taste, Sollicited her longing eye; yet first Pausing a while, thus to her self she mus'd. Great are thy Vertues, doubtless, best of Fruits, Though kept from Man, & worthy to be admir'd, Whose taste, too long forborn, at first assay Gave elocution to the mute, and taught The Tongue not made for Speech to speak thy praise: Thy praise hee also who forbids thy use, Conceales not from us, naming thee the Tree Of Knowledge, knowledge both of good and evil; Forbids us then to taste, but his forbidding Commends thee more, while it inferrs the good By thee communicated, and our want: For good unknown, sure is not had, or had And yet unknown, is as not had at all. In plain then, what forbids he but to know, Forbids us good, forbids us to be wise? Such prohibitions binde not. But if Death Bind us with after-bands, what profits then Our inward freedom? In the day we eate Of this fair Fruit, our doom is, we shall die. How dies the Serpent? hee hath eat'n and lives, And knows, and speaks, and reasons, and discernes, Irrational till then. For us alone Was death invented? or to us deni'd This intellectual food, for beasts reserv'd? For Beasts it seems: yet that one Beast which first Hath tasted, envies not, but brings with joy The good befall'n him, Author unsuspect, Friendly to man, farr from deceit or guile. What fear I then, rather what know to feare Under this ignorance of Good and Evil, Of God or Death, of Law or Penaltie? Here grows the Cure of all, this Fruit Divine, Fair to the Eye, inviting to the Taste, Of vertue to make wise: what hinders then To reach, and feed at once both Bodie and Mind? So saying, her rash hand in evil hour Forth reaching to the Fruit, she pluck'd, she eat: Earth felt the wound, and Nature from her seat Sighing through all her Works gave signs of woe, That all was lost. Back to the Thicket slunk The guiltie Serpent, and well might, for EVE Intent now wholly on her taste, naught else Regarded, such delight till then, as seemd, In Fruit she never tasted, whether true Or fansied so, through expectation high Of knowledg, nor was God-head from her thought. Greedily she ingorg'd without restraint, And knew not eating Death: Satiate at length, And hight'nd as with Wine, jocond and boon, Thus to her self she pleasingly began. O Sovran, vertuous, precious of all Trees In Paradise, of operation blest To Sapience, hitherto obscur'd, infam'd, And thy fair Fruit let hang, as to no end Created; but henceforth my early care, Not without Song, each Morning, and due praise Shall tend thee, and the fertil burden ease Of thy full branches offer'd free to all; Till dieted by thee I grow mature In knowledge, as the Gods who all things know; Though others envie what they cannot give; For had the gift bin theirs, it had not here Thus grown. Experience, next to thee I owe, Best guide; not following thee, I had remaind In ignorance, thou op'nst Wisdoms way, And giv'st access, though secret she retire. And I perhaps am secret; Heav'n is high, High and remote to see from thence distinct Each thing on Earth; and other care perhaps May have diverted from continual watch Our great Forbidder, safe with all his Spies About him. But to ADAM in what sort Shall I appeer? shall I to him make known As yet my change, and give him to partake Full happiness with mee, or rather not, But keep the odds of Knowledge in my power Without Copartner? so to add what wants In Femal Sex, the more to draw his Love, And render me more equal, and perhaps A thing not undesireable, somtime Superior; for inferior who is free? This may be well: but what if God have seen, And Death ensue? then I shall be no more, And ADAM wedded to another EVE, Shall live with her enjoying, I extinct; A death to think. Confirm'd then I resolve, ADAM shall share with me in bliss or woe: So dear I love him, that with him all deaths I could endure; without him live no life. So saying, from the Tree her step she turnd, But first low Reverence don, as to the power That dwelt within, whose presence had infus'd Into the plant sciential sap, deriv'd From Nectar, drink of Gods. ADAM the while Waiting desirous her return, had wove Of choicest Flours a Garland to adorne Her Tresses, and her rural labours crown As Reapers oft are wont thir Harvest Queen. Great joy he promis'd to his thoughts, and new Solace in her return, so long delay'd; Yet oft his heart, divine of somthing ill, Misgave him; hee the faultring measure felt; And forth to meet her went, the way she took That Morn when first they parted; by the Tree Of Knowledge he must pass, there he her met, Scarse from the Tree returning; in her hand A bough of fairest fruit that downie smil'd, New gatherd, and ambrosial smell diffus'd. To him she hasted, in her face excuse Came Prologue, and Apologie to prompt, Which with bland words at will she thus addrest. Hast thou not wonderd, ADAM, at my stay? Thee I have misst, and thought it long, depriv'd Thy presence, agonie of love till now Not felt, nor shall be twice, for never more Mean I to trie, what rash untri'd I sought, The paine of absence from thy sight. But strange Hath bin the cause, and wonderful to heare: This Tree is not as we are told, a Tree Of danger tasted, nor to evil unknown Op'ning the way, but of Divine effect To open Eyes, and make them Gods who taste; And hath bin tasted such; the Serpent wise, Or not restraind as wee, or not obeying, Hath eat'n of the fruit, and is become, Not dead, as we are threatn'd, but thenceforth Endu'd with human voice and human sense, Reasoning to admiration, and with mee Perswasively hath so prevaild, that I Have also tasted, and have also found Th' effects to correspond, opener mine Eyes, Dimm erst, dilated Spirits, ampler Heart, And growing up to Godhead; which for thee Chiefly I sought, without thee can despise. For bliss, as thou hast part, to me is bliss, Tedious, unshar'd with thee, and odious soon. Thou therefore also taste, that equal Lot May joyne us, equal Joy, as equal Love; Least thou not tasting, different degree Disjoyne us, and I then too late renounce Deitie for thee, when Fate will not permit. Thus EVE with Countnance blithe her storie told; But in her Cheek distemper flushing glowd. On th' other side, ADAM, soon as he heard The fatal Trespass don by EVE, amaz'd, Astonied stood and Blank, while horror chill Ran through his veins, and all his joynts relax'd; From his slack hand the Garland wreath'd for EVE Down drop'd, and all the faded Roses shed: Speechless he stood and pale, till thus at length First to himself he inward silence broke. O fairest of Creation, last and best Of all Gods Works, Creature in whom excell'd Whatever can to fight or thought be found, Holy, divine, good, amiable, or sweet! How art thou lost, how on a sudden lost, Defac't, deflourd, and now to Death devote? Rather how hast thou yeelded to transgress The strict forbiddance, how to violate The sacred Fruit forbidd'n! som cursed fraud Of Enemie hath beguil'd thee, yet unknown, And mee with thee hath ruind, for with thee Certain my resolution is to Die; How can I live without thee, how forgoe Thy sweet Converse and Love so dearly joyn'd, To live again in these wilde Woods forlorn? Should God create another EVE, and I Another Rib afford, yet loss of thee Would never from my heart; no no, I feel The Link of Nature draw me: Flesh of Flesh, Bone of my Bone thou art, and from thy State Mine never shall be parted, bliss or woe. So having said, as one from sad dismay Recomforted, and after thoughts disturbd Submitting to what seemd remediless, Thus in calme mood his Words to EVE he turnd. Bold deed thou hast presum'd, adventrous EVE, And peril great provok't, who thus hast dar'd Had it bin onely coveting to Eye That sacred Fruit, sacred to abstinence, Much more to taste it under banne to touch. But past who can recall, or don undoe? Not God omnipotent, for Fate, yet so Perhaps thou shalt not Die, perhaps the Fact Is not so hainous now, foretasted Fruit, Profan'd first by the Serpent, by him first Made common and unhallowd: ere one tastes; Nor yet on him found deadly; he yet lives, Lives, as thou saidst, and gaines to live as Man Higher degree of Life, inducement strong To us, as likely tasting to attaine Proportional ascent, which cannot be But to be Gods, or Angels Demi-gods. Nor can I think that God, Creator wise, Though threatning, will in earnest so destroy Us his prime Creatures, dignifi'd so high, Set over all his Works, which in our Fall, For us created, needs with us must faile, Dependent made; so God shall uncreate, Be frustrate, do, undo, and labour loose, Not well conceav'd of God, who though his Power Creation could repeate, yet would be loath Us to abolish, least the Adversary Triumph and say; Fickle their State whom God Most Favors, who can please him long? Mee first He ruind, now Mankind; whom will he next? Matter of scorne, not to be given the Foe. However I with thee have fixt my Lot, Certain to undergoe like doom, if Death Consort with thee, Death is to mee as Life; So forcible within my heart I feel The Bond of Nature draw me to my owne, My own in thee, for what thou art is mine; Our State cannot be severd, we are one, One Flesh; to loose thee were to loose my self. So ADAM, and thus EVE to him repli'd. O glorious trial of exceeding Love, Illustrious evidence, example high! Ingaging me to emulate, but short Of thy perfection, how shall I attaine, ADAM, from whose deare side I boast me sprung, And gladly of our Union heare thee speak, One Heart, one Soul in both; whereof good prooff This day affords, declaring thee resolvd, Rather then Death or aught then Death more dread Shall separate us, linkt in Love so deare, To undergoe with mee one Guilt, one Crime, If any be, of tasting this fair Fruit, Whose vertue, for of good still good proceeds, Direct, or by occasion hath presented This happie trial of thy Love, which else So eminently never had bin known. Were it I thought Death menac't would ensue This my attempt, I would sustain alone The worst, and not perswade thee, rather die Deserted, then oblige thee with a fact Pernicious to thy Peace, chiefly assur'd Remarkably so late of thy so true, So faithful Love unequald; but I feel Farr otherwise th' event, not Death, but Life Augmented, op'nd Eyes, new Hopes, new Joyes, Taste so Divine, that what of sweet before Hath toucht my sense, flat seems to this, and harsh. On my experience, ADAM, freely taste, And fear of Death deliver to the Windes. So saying, she embrac'd him, and for joy Tenderly wept, much won that he his Love Had so enobl'd, as of choice to incurr Divine displeasure for her sake, or Death. In recompence (for such compliance bad Such recompence best merits) from the bough She gave him of that fair enticing Fruit With liberal hand: he scrupl'd not to eat Against his better knowledge, not deceav'd, But fondly overcome with Femal charm. Earth trembl'd from her entrails, as again In pangs, and Nature gave a second groan, Skie lowr'd, and muttering Thunder, som sad drops Wept at compleating of the mortal Sin Original; while ADAM took no thought, Eating his fill, nor EVE to iterate Her former trespass fear'd, the more to soothe Him with her lov'd societie, that now As with new Wine intoxicated both They swim in mirth, and fansie that they feel Divinitie within them breeding wings Wherewith to scorn the Earth: but that false Fruit Farr other operation first displaid, Carnal desire enflaming, hee on EVE Began to cast lascivious Eyes, she him As wantonly repaid; in Lust they burne: Till ADAM thus 'gan EVE to dalliance move. EVE, now I see thou art exact of taste, And elegant, of Sapience no small part, Since to each meaning savour we apply, And Palate call judicious; I the praise Yeild thee, so well this day thou hast purvey'd. Much pleasure we have lost, while we abstain'd From this delightful Fruit, nor known till now True relish, tasting; if such pleasure be In things to us forbidden, it might be wish'd, For this one Tree had bin forbidden ten. But come, so well refresh't, now let us play, As meet is, after such delicious Fare; For never did thy Beautie since the day I saw thee first and wedded thee, adorn'd With all perfections, so enflame my sense With ardor to enjoy thee, fairer now Then ever, bountie of this vertuous Tree. So said he, and forbore not glance or toy Of amorous intent, well understood Of EVE, whose Eye darted contagious Fire. Her hand he seis'd, and to a shadie bank, Thick overhead with verdant roof imbowr'd He led her nothing loath; Flours were the Couch, Pansies, and Violets, and Asphodel, And Hyacinth, Earths freshest softest lap. There they thir fill of Love and Loves disport Took largely, of thir mutual guilt the Seale, The solace of thir sin, till dewie sleep Oppress'd them, wearied with thir amorous play. Soon as the force of that fallacious Fruit, That with exhilerating vapour bland About thir spirits had plaid, and inmost powers Made erre, was now exhal'd, and grosser sleep Bred of unkindly fumes, with conscious dreams Encumberd, now had left them, up they rose As from unrest, and each the other viewing, Soon found thir Eyes how op'nd, and thir minds How dark'nd; innocence, that as a veile Had shadow'd them from knowing ill, was gon, Just confidence, and native righteousness, And honour from about them, naked left To guiltie shame hee cover'd, but his Robe Uncover'd more. So rose the DANITE strong HERCULEAN SAMSON from the Harlot-lap Of PHILISTEAN DALILAH, and wak'd Shorn of his strength, They destitute and bare Of all thir vertue: silent, and in face Confounded long they sate, as struck'n mute, Till ADAM, though not less then EVE abasht, At length gave utterance to these words constraind. O EVE, in evil hour thou didst give care To that false Worm, of whomsoever taught To counterfet Mans voice, true in our Fall, False in our promis'd Rising; since our Eyes Op'nd we find indeed, and find we know Both Good and Evil, Good lost and Evil got, Bad Fruit of Knowledge, if this be to know, Which leaves us naked thus, of Honour void, Of Innocence, of Faith, of Puritie, Our wonted Ornaments now soild and staind, And in our Faces evident the signes Of foul concupiscence; whence evil store; Even shame, the last of evils; of the first Be sure then. How shall I behold the face Henceforth of God or Angel, earst with joy And rapture so oft beheld? those heav'nly shapes Will dazle now this earthly, with thir blaze Insufferably bright. O might I here In solitude live savage, in some glad Obscur'd, where highest Woods impenetrable To Starr or Sun-light, spread thir umbrage broad, And brown as Evening: Cover me ye Pines, Ye Cedars, with innumerable boughs Hide me, where I may never see them more. But let us now, as in bad plight, devise What best may for the present serve to hide The Parts of each from other, that seem most To shame obnoxious, and unseemliest seen, Some Tree whose broad smooth Leaves together sowd, And girded on our loyns, may cover round Those middle parts, that this new commer, Shame, There sit not, and reproach us as unclean. So counsel'd hee, and both together went Into the thickest Wood, there soon they chose The Figtree, not that kind for Fruit renown'd, But such as at this day to INDIANS known In MALABAR or DECAN spreds her Armes Braunching so broad and long, that in the ground The bended Twigs take root, and Daughters grow About the Mother Tree, a Pillard shade High overarch't, and echoing Walks between; There oft the INDIAN Herdsman shunning heate Shelters in coole, and tends his pasturing Herds At Loopholes cut through thickest shade: Those Leaves They gatherd, broad as AMAZONIAN Targe, And with what skill they had, together sowd, To gird thir waste, vain Covering if to hide Thir guilt and dreaded shame; O how unlike To that first naked Glorie. Such of late COLUMBUS found th' AMERICAN to girt With featherd Cincture, naked else and wilde Among the Trees on Iles and woodie Shores. Thus fenc't, and as they thought, thir shame in part Coverd, but not at rest or ease of Mind, They sate them down to weep, nor onely Teares Raind at thir Eyes, but high Winds worse within Began to rise, high Passions, Anger, Hate, Mistrust, Suspicion, Discord, and shook sore Thir inward State of Mind, calme Region once And full of Peace, now tost and turbulent: For Understanding rul'd not, and the Will Heard not her lore, both in subjection now To sensual Appetite, who from beneathe Usurping over sovran Reason claimd Superior sway: From thus distemperd brest, ADAM, estrang'd in look and alterd stile, Speech intermitted thus to EVE renewd. Would thou hadst heark'nd to my words, & stai'd With me, as I besought thee, when that strange Desire of wandring this unhappie Morn, I know not whence possessd thee; we had then Remaind still happie, not as now, despoild Of all our good, sham'd, naked, miserable. Let none henceforth seek needless cause to approve The Faith they owe; when earnestly they seek Such proof, conclude, they then begin to faile. To whom soon mov'd with touch of blame thus EVE. What words have past thy Lips, ADAM severe, Imput'st thou that to my default, or will Of wandering, as thou call'st it, which who knows But might as ill have happ'nd thou being by, Or to thy self perhaps: hadst thou bin there, Or bere th' attempt, thou couldst not have discernd Fraud in the Serpent, speaking as he spake; No ground of enmitie between us known, Why hee should mean me ill, or seek to harme. Was I to have never parted from thy side? As good have grown there still a liveless Rib. Being as I am, why didst not thou the Head Command me absolutely not to go, Going into such danger as thou saidst? Too facil then thou didst not much gainsay, Nay, didst permit, approve, and fair dismiss. Hadst thou bin firm and fixt in thy dissent, Neither had I transgress'd, nor thou with mee. To whom then first incenst ADAM repli'd. Is this the Love, is the recompence Of mine to thee, ingrateful EVE, exprest Immutable when thou wert lost, not I, Who might have liv'd and joyd immortal bliss, Yet willingly chose rather Death with thee: And am I now upbraided, as the cause Of thy transgressing? not enough severe, It seems, in thy restraint: what could I more? I warn'd thee, I admonish'd thee, foretold The danger, and the lurking Enemie That lay in wait; beyond this had bin force, And force upon free Will hath here no place. But confidence then bore thee on, secure Either to meet no danger, or to finde Matter of glorious trial; and perhaps I also err'd in overmuch admiring What seemd in thee so perfet, that I thought No evil durst attempt thee, but I rue That errour now, which is become my crime, And thou th' accuser. Thus it shall befall Him who to worth in Women overtrusting Lets her Will rule; restraint she will not brook, And left to her self, if evil thence ensue, Shee first his weak indulgence will accuse. Thus they in mutual accusation spent The fruitless hours, but neither self-condemning And of thir vain contest appeer'd no end. THE END OF THE EIGHTH BOOK. PARADISE LOST BOOK IX. Meanwhile the hainous and despightfull act Of SATAN done in Paradise, and how Hee in the Serpent had perverted EVE, Her Husband shee, to taste the fatall fruit, Was known in Heav'n; for what can scape the Eye Of God All-seeing, or deceave his Heart Omniscient, who in all things wise and just, Hinder'd not SATAN to attempt the minde Of Man, with strength entire, and free Will arm'd, Complete to have discover'd and repulst Whatever wiles of Foe or seeming Friend. For still they knew, and ought to have still remember'd The high Injunction not to taste that Fruit, Whoever tempted; which they not obeying, Incurr'd, what could they less, the penaltie, And manifold in sin, deserv'd to fall. Up into Heav'n from Paradise in hast Th' Angelic Guards ascended, mute and sad For Man, for of his state by this they knew, Much wondring how the suttle Fiend had stoln Entrance unseen. Soon as th' unwelcome news From Earth arriv'd at Heaven Gate, displeas'd All were who heard, dim sadness did not spare That time Celestial visages, yet mixt With pitie, violated not thir bliss. About the new-arriv'd, in multitudes Th' ethereal People ran, to hear and know How all befell: they towards the Throne Supream Accountable made haste to make appear With righteous plea, thir utmost vigilance, And easily approv'd; when the most High Eternal Father from his secret Cloud, Amidst in Thunder utter'd thus his voice. Assembl'd Angels, and ye Powers return'd From unsuccessful charge, be not dismaid, Nor troubl'd at these tidings from the Earth, Which your sincerest care could not prevent, Foretold so lately what would come to pass, When first this Tempter cross'd the Gulf from Hell. I told ye then he should prevail and speed On his bad Errand, Man should be seduc't And flatter'd out of all, believing lies Against his Maker; no Decree of mine Concurring to necessitate his Fall, Or touch with lightest moment of impulse His free Will, to her own inclining left In eevn scale. But fall'n he is, and now What rests, but that the mortal Sentence pass On his transgression, Death denounc't that day, Which he presumes already vain and void, Because not yet inflicted, as he fear'd, By some immediate stroak; but soon shall find Forbearance no acquittance ere day end. Justice shall not return as bountie scorn'd. But whom send I to judge them? whom but thee Vicegerent Son, to thee I have transferr'd All Judgement, whether in Heav'n, or Earth; or Hell. Easie it may be seen that I intend Mercie collegue with Justice, sending thee Mans Friend, his Mediator, his design'd Both Ransom and Redeemer voluntarie, And destin'd Man himself to judge Man fall'n. So spake the Father, and unfoulding bright Toward the right hand his Glorie, on the Son Blaz'd forth unclouded Deitie; he full Resplendent all his Father manifest Express'd, and thus divinely answer'd milde. Father Eternal, thine is to decree, Mine both in Heav'n and Earth to do thy will Supream, that thou in mee thy Son belov'd Mayst ever rest well pleas'd. I go to judge On Earth these thy transgressors, but thou knowst, Whoever judg'd, the worst on mee must light, When time shall be, for so I undertook Before thee; and not repenting, this obtaine Of right, that I may mitigate thir doom On me deriv'd, yet I shall temper so Justice with Mercie, as may illustrate most Them fully satisfied, and thee appease. Attendance none shall need, nor Train, where none Are to behold the Judgement, but the judg'd, Those two; the third best absent is condemn'd, Convict by flight, and Rebel to all Law Conviction to the Serpent none belongs. Thus saying, from his radiant Seat he rose Of high collateral glorie: him Thrones and Powers, Princedoms, and Dominations ministrant Accompanied to Heaven Gate, from whence EDEN and all the Coast in prospect lay. Down he descended strait; the speed of Gods Time counts not, though with swiftest minutes wing'd. Now was the Sun in Western cadence low From Noon, and gentle Aires due at thir hour To fan the Earth now wak'd, and usher in The Eevning coole when he from wrauth more coole Came the mild Judge and Intercessor both To sentence Man: the voice of God they heard Now walking in the Garden, by soft windes Brought to thir Ears, while day declin'd, they heard And from his presence hid themselves among The thickest Trees, both Man and Wife, till God Approaching, thus to ADAM call'd aloud. Where art thou ADAM, wont with joy to meet My coming seen far off? I miss thee here, Not pleas'd, thus entertaind with solitude, Where obvious dutie erewhile appear'd unsaught: Or come I less conspicuous, or what change Absents thee, or what chance detains? Come forth. He came, and with him EVE, more loth, though first To offend, discount'nanc't both, and discompos'd; Love was not in thir looks, either to God Or to each other, but apparent guilt, And shame, and perturbation, and despaire, Anger, and obstinacie, and hate, and guile. Whence ADAM faultring long, thus answer'd brief. I heard thee in the Garden, and of thy voice Affraid, being naked, hid my self. To whom The gracious Judge without revile repli'd. My voice thou oft hast heard, and hast not fear'd, But still rejoyc't, how is it now become So dreadful to thee? that thou art naked, who Hath told thee? hast thou eaten of the Tree Whereof I gave thee charge thou shouldst not eat? To whom thus ADAM sore beset repli'd. O Heav'n! in evil strait this day I stand Before my Judge, either to undergoe My self the total Crime, or to accuse My other self, the partner of my life; Whose failing, while her Faith to me remaines, I should conceal, and not expose to blame By my complaint; but strict necessitie Subdues me, and calamitous constraint, Least on my head both sin and punishment, However insupportable, be all Devolv'd; though should I hold my peace, yet thou Wouldst easily detect what I conceale. This Woman whom thou mad'st to be my help, And gav'st me as thy perfet gift, so good, So fit, so acceptable, so Divine, That from her hand I could suspect no ill, And what she did, whatever in it self, Her doing seem'd to justifie the deed; Shee gave me of the Tree, and I did eate. To whom the sovran Presence thus repli'd. Was shee thy God, that her thou didst obey Before his voice, or was shee made thy guide, Superior, or but equal, that to her Thou did'st resigne thy Manhood, and the Place Wherein God set thee above her made of thee, And for thee, whose perfection farr excell'd Hers in all real dignitie: Adornd She was indeed, and lovely to attract Thy Love, not thy Subjection, and her Gifts Were such as under Government well seem'd, Unseemly to beare rule, which was thy part And person, had'st thou known thy self aright. So having said, he thus to EVE in few: Say Woman, what is this which thou hast done? To whom sad EVE with shame nigh overwhelm'd, Confessing soon, yet not before her Judge Bold or loquacious, thus abasht repli'd. The Serpent me beguil'd and I did eate. Which when the Lord God heard, without delay To Judgement he proceeded on th' accus'd Serpent though brute, unable to transferre The Guilt on him who made him instrument Of mischief, and polluted from the end Of his Creation; justly then accurst, As vitiated in Nature: more to know Concern'd not Man (since he no further knew) Nor alter'd his offence; yet God at last To Satan first in sin his doom apply'd, Though in mysterious terms, judg'd as then best: And on the Serpent thus his curse let fall. Because thou hast done this, thou art accurst Above all Cattel, each Beast of the Field; Upon thy Belly groveling thou shalt goe, And dust shalt eat all the days of thy Life. Between Thee and the Woman I will put Enmitie, and between thine and her Seed; Her Seed shall bruise thy head, thou bruise his heel. So spake this Oracle, then verifi'd When JESUS son of MARY second EVE, Saw Satan fall like Lightning down from Heav'n, Prince of the Aire; then rising from his Grave Spoild Principalities and Powers, triumpht In open shew, and with ascention bright Captivity led captive through the Aire, The Realme it self of Satan long usurpt, Whom he shall tread at last under our feet; Eevn hee who now foretold his fatal bruise, And to the Woman thus his Sentence turn'd. Thy sorrow I will greatly multiplie By thy Conception; Children thou shalt bring In sorrow forth, and to thy Husbands will Thine shall submit, hee over thee shall rule. On ADAM last thus judgement he pronounc'd. Because thou hast heark'nd to the voice of thy Wife, And eaten of the Tree concerning which I charg'd thee, saying: Thou shalt not eate thereof, Curs'd is the ground for thy sake, thou in sorrow Shalt eate thereof all the days of thy Life; Thornes also and Thistles it shall bring thee forth Unbid, and thou shalt eate th' Herb of th' Field, In the sweat of thy Face shalt thou eate Bread, Till thou return unto the ground, for thou Out of the ground wast taken, know thy Birth, For dust thou art, and shalt to dust returne. So judg'd he Man, both Judge and Saviour sent, And th' instant stroke of Death denounc't that day Remov'd farr off; then pittying how they stood Before him naked to the aire, that now Must suffer change, disdain'd not to begin Thenceforth the forme of servant to assume, As when he wash'd his servants feet, so now As Father of his Familie he clad Thir nakedness with Skins of Beasts, or slain, Or as the Snake with youthful Coate repaid; And thought not much to cloath his Enemies: Nor hee thir outward onely with the Skins Of Beasts, but inward nakedness, much more Opprobrious, with his Robe of righteousness, Araying cover'd from his Fathers sight. To him with swift ascent he up returnd, Into his blissful bosom reassum'd In glory as of old, to him appeas'd All, though all-knowing, what had past with Man Recounted, mixing intercession sweet. Meanwhile ere thus was sin'd and judg'd on Earth, Within the Gates of Hell sate Sin and Death, In counterview within the Gates, that now Stood open wide, belching outrageous flame Farr into CHAOS, since the Fiend pass'd through, Sin opening, who thus now to Death began. O Son, why sit we here each other viewing Idlely, while Satan our great Author thrives In other Worlds, and happier Seat provides For us his ofspring deare? It cannot be But that success attends him; if mishap, Ere this he had return'd, with fury driv'n By his Avenger, since no place like this Can fit his punishment, or their revenge. Methinks I feel new strength within me rise, Wings growing, and Dominion giv'n me large Beyond this Deep; whatever drawes me on, Or sympathie, or som connatural force Powerful at greatest distance to unite With secret amity things of like kinde By secretest conveyance. Thou my Shade Inseparable must with mee along: For Death from Sin no power can separate. But least the difficultie of passing back Stay his returne perhaps over this Gulfe Impassable, impervious, let us try Adventrous work, yet to thy power and mine Not unagreeable, to found a path Over this Maine from Hell to that new World Where Satan now prevailes, a Monument Of merit high to all th' infernal Host, Easing thir passage hence, for intercourse, Or transmigration, as thir lot shall lead. Nor can I miss the way, so strongly drawn By this new felt attraction and instinct. Whom thus the meager Shadow answerd soon. Goe whither Fate and inclination strong Leads thee, I shall not lag behinde, nor erre The way, thou leading, such a sent I draw Of carnage, prey innumerable, and taste The savour of Death from all things there that live: Nor shall I to the work thou enterprisest Be wanting, but afford thee equal aid. So saying, with delight he snuff'd the smell Of mortal change on Earth. As when a flock Of ravenous Fowl, though many a League remote, Against the day of Battel, to a Field, Where Armies lie encampt, come flying, lur'd With sent of living Carcasses design'd For death, the following day, in bloodie fight. So sented the grim Feature, and upturn'd His Nostril wide into the murkie Air, Sagacious of his Quarrey from so farr. Then Both from out Hell Gates into the waste Wide Anarchie of CHAOS damp and dark Flew divers, & with Power (thir Power was great) Hovering upon the Waters; what they met Solid or slimie, as in raging Sea Tost up and down, together crowded drove From each side shoaling towards the mouth of Hell. As when two Polar Winds blowing adverse Upon the CRONIAN Sea, together drive Mountains of Ice, that stop th' imagin'd way Beyond PETSORA Eastward, to the rich CATHAIAN Coast. The aggregated Soyle Death with his Mace petrific, cold and dry, As with a Trident smote, and fix't as firm As DELOS floating once; the rest his look Bound with GORGONIAN rigor not to move, And with ASPHALTIC slime; broad as the Gate, Deep to the Roots of Hell the gather'd beach They fasten'd, and the Mole immense wraught on Over the foaming deep high Archt, a Bridge Of length prodigious joyning to the Wall Immoveable of this now fenceless world Forfeit to Death; from hence a passage broad, Smooth, easie, inoffensive down to Hell. So, if great things to small may be compar'd, XERXES, the Libertie of GREECE to yoke, From SUSA his MEMNONIAN Palace high Came to the Sea, and over HELLESPONT Bridging his way, EUROPE with ASIA joyn'd, And scourg'd with many a stroak th' indignant waves. Now had they brought the work by wondrous Art Pontifical, a ridge of pendent Rock Over the vext Abyss, following the track Of SATAN, to the selfsame place where hee First lighted from his Wing, and landed safe From out of CHAOS to the outside bare Of this round World: with Pinns of Adamant And Chains they made all fast, too fast they made And durable; and now in little space The Confines met of Empyrean Heav'n And of this World, and on the left hand Hell With long reach interpos'd; three sev'ral wayes In sight, to each of these three places led. And now thir way to Earth they had descri'd, To Paradise first tending, when behold SATAN in likeness of an Angel bright Betwixt the CENTAURE and the SCORPION stearing His ZENITH, while the Sun in ARIES rose: Disguis'd he came, but those his Children dear Thir Parent soon discern'd, though in disguise. Hee, after EVE seduc't, unminded slunk Into the Wood fast by, and changing shape To observe the sequel, saw his guileful act By EVE, though all unweeting, seconded Upon her Husband, saw thir shame that sought Vain covertures; but when he saw descend The Son of God to judge them, terrifi'd Hee fled, not hoping to escape, but shun The present, fearing guiltie what his wrauth Might suddenly inflict; that past, return'd By Night, and listning where the hapless Paire Sate in thir sad discourse, and various plaint, Thence gatherd his own doom, which understood Not instant, but of future time. With joy And tidings fraught, to Hell he now return'd, And at the brink of CHAOS, neer the foot Of this new wondrous Pontifice, unhop't Met who to meet him came, his Ofspring dear. Great joy was at thir meeting, and at sight Of that stupendious Bridge his joy encreas'd. Long hee admiring stood, till Sin, his faire Inchanting Daughter, thus the silence broke. O Parent, these are thy magnific deeds, Thy Trophies, which thou view'st as not thine own, Thou art thir Author and prime Architect: For I no sooner in my Heart divin'd, My Heart, which by a secret harmonie Still moves with thine, joyn'd in connexion sweet, That thou on Earth hadst prosper'd, which thy looks Now also evidence, but straight I felt Though distant from thee Worlds between, yet felt That I must after thee with this thy Son; Such fatal consequence unites us three: Hell could no longer hold us in her bounds, Nor this unvoyageable Gulf obscure Detain from following thy illustrious track. Thou hast atchiev'd our libertie, confin'd Within Hell Gates till now, thou us impow'rd To fortifie thus farr, and overlay With this portentous Bridge the dark Abyss. Thine now is all this World, thy vertue hath won What thy hands builded not, thy Wisdom gain'd With odds what Warr hath lost, and fully aveng'd Our foile in Heav'n; here thou shalt Monarch reign, There didst not; there let him still Victor sway, As Battel hath adjudg'd, from this new World Retiring, by his own doom alienated, And henceforth Monarchie with thee divide Of all things, parted by th' Empyreal bounds, His Quadrature, from thy Orbicular World, Or trie thee now more dang'rous to his Throne. Whom thus the Prince of Darkness answerd glad. Fair Daughter, and thou Son and Grandchild both, High proof ye now have giv'n to be the Race Of SATAN (for I glorie in the name, Antagonist of Heav'ns Almightie King) Amply have merited of me, of all Th' Infernal Empire, that so neer Heav'ns dore Triumphal with triumphal act have met, Mine with this glorious Work, & made one Realm Hell and this World, one Realm, one Continent Of easie thorough-fare. Therefore while I Descend through Darkness, on your Rode with ease To my associate Powers, them to acquaint With these successes, and with them rejoyce, You two this way, among those numerous Orbs All yours, right down to Paradise descend; There dwell & Reign in bliss, thence on the Earth Dominion exercise and in the Aire, Chiefly on Man, sole Lord of all declar'd, Him first make sure your thrall, and lastly kill. My Substitutes I send ye, and Create Plenipotent on Earth, of matchless might Issuing from mee: on your joynt vigor now My hold of this new Kingdom all depends, Through Sin to Death expos'd by my exploit. If your joynt power prevaile, th' affaires of Hell No detriment need feare, goe and be strong. So saying he dismiss'd them, they with speed Thir course through thickest Constellations held Spreading thir bane; the blasted Starrs lookt wan, And Planets, Planet-strook, real Eclips Then sufferd. Th' other way SATAN went down The Causey to Hell Gate; on either side Disparted CHAOS over built exclaimd, And with rebounding surge the barrs assaild, That scorn'd his indignation: through the Gate, Wide open and unguarded, SATAN pass'd, And all about found desolate; for those Appointed to sit there, had left thir charge, Flown to the upper World; the rest were all Farr to the inland retir'd, about the walls Of PANDEMONIUM, Citie and proud seate Of LUCIFER, so by allusion calld, Of that bright Starr to SATAN paragond. There kept thir Watch the Legions, while the Grand In Council sate, sollicitous what chance Might intercept thir Emperour sent, so hee Departing gave command, and they observ'd. As when the TARTAR from his RUSSIAN Foe By ASTRACAN over the Snowie Plaines Retires, or BACTRIAN Sophi from the hornes Of TURKISH Crescent, leaves all waste beyond The Realme of ALADULE, in his retreate To TAURIS or CASBEEN. So these the late Heav'n-banisht Host, left desert utmost Hell Many a dark League, reduc't in careful Watch Round thir Metropolis, and now expecting Each hour their great adventurer from the search Of Forrein Worlds: he through the midst unmarkt, In shew plebeian Angel militant Of lowest order, past; and from the dore Of that PLUTONIAN Hall, invisible Ascended his high Throne, which under state Of richest texture spred, at th' upper end Was plac't in regal lustre. Down a while He sate, and round about him saw unseen: At last as from a Cloud his fulgent head And shape Starr bright appeer'd, or brighter, clad With what permissive glory since his fall Was left him, or false glitter: All amaz'd At that so sudden blaze the STYGIAN throng Bent thir aspect, and whom they wish'd beheld, Thir mighty Chief returnd: loud was th' acclaime: Forth rush'd in haste the great consulting Peers, Rais'd from thir dark DIVAN, and with like joy Congratulant approach'd him, who with hand Silence, and with these words attention won. Thrones, Dominations, Princedoms, Vertues, Powers, For in possession such, not onely of right, I call ye and declare ye now, returnd Successful beyond hope, to lead ye forth Triumphant out of this infernal Pit Abominable, accurst, the house of woe, And Dungeon of our Tyrant: Now possess, As Lords, a spacious World, to our native Heaven Little inferiour, by my adventure hard With peril great atchiev'd. Long were to tell What I have don, what sufferd, with what paine Voyag'd the unreal, vast, unbounded deep Of horrible confusion, over which By Sin and Death a broad way now is pav'd To expedite your glorious march; but I Toild out my uncouth passage, forc't to ride Th' untractable Abysse, plung'd in the womb Of unoriginal NIGHT and CHAOS wilde, That jealous of thir secrets fiercely oppos'd My journey strange, with clamorous uproare Protesting Fate supreame; thence how I found The new created World, which fame in Heav'n Long had foretold, a Fabrick wonderful Of absolute perfection, therein Man Plac't in a Paradise, by our exile Made happie: Him by fraud I have seduc'd From his Creator, and the more to increase Your wonder, with an Apple; he thereat Offended, worth your laughter, hath giv'n up Both his beloved Man and all his World, To Sin and Death a prey, and so to us, Without our hazard, labour or allarme, To range in, and to dwell, and over Man To rule, as over all he should have rul'd. True is, mee also he hath judg'd, or rather Mee not, but the brute Serpent in whose shape Man I deceav'd: that which to mee belongs, Is enmity, which he will put between Mee and Mankinde; I am to bruise his heel; His Seed, when is not set, shall bruise my head: A World who would not purchase with a bruise, Or much more grievous pain? Ye have th' account Of my performance: What remaines, ye Gods, But up and enter now into full bliss. So having said, a while he stood, expecting Thir universal shout and high applause To fill his eare, when contrary he hears On all sides, from innumerable tongues A dismal universal hiss, the sound Of public scorn; he wonderd, but not long Had leasure, wondring at himself now more; His Visage drawn he felt to sharp and spare, His Armes clung to his Ribs, his Leggs entwining Each other, till supplanted down he fell A monstrous Serpent on his Belly prone, Reluctant, but in vaine, a greater power Now rul'd him, punisht in the shape he sin'd, According to his doom: he would have spoke, But hiss for hiss returnd with forked tongue To forked tongue, for now were all transform'd Alike, to Serpents all as accessories To his bold Riot: dreadful was the din Of hissing through the Hall, thick swarming now With complicated monsters, head and taile, Scorpion and Asp, and AMPHISBAENA dire, CERASTES hornd, HYDRUS, and ELLOPS drear, And DIPSAS (Not so thick swarm'd once the Soil Bedropt with blood of Gorgon, or the Isle OPHIUSA) but still greatest hee the midst, Now Dragon grown, larger then whom the Sun Ingenderd in the PYTHIAN Vale on slime, Huge PYTHON, and his Power no less he seem'd Above the rest still to retain; they all Him follow'd issuing forth to th' open Field, Where all yet left of that revolted Rout Heav'n-fall'n, in station stood or just array, Sublime with expectation when to see In Triumph issuing forth thir glorious Chief; They saw, but other sight instead, a crowd Of ugly Serpents; horror on them fell, And horrid sympathie; for what they saw, They felt themselvs now changing; down thir arms, Down fell both Spear and Shield, down they as fast, And the dire hiss renew'd, and the dire form Catcht by Contagion, like in punishment, As in thir crime. Thus was th' applause they meant, Turnd to exploding hiss, triumph to shame Cast on themselves from thir own mouths. There stood A Grove hard by, sprung up with this thir change, His will who reigns above, to aggravate Thir penance, laden with fair Fruit, like that VVhich grew in Paradise, the bait of EVE Us'd by the Tempter: on that prospect strange Thir earnest eyes they fix'd, imagining For one forbidden Tree a multitude Now ris'n, to work them furder woe or shame; Yet parcht with scalding thurst and hunger fierce, Though to delude them sent, could not abstain, But on they rould in heaps, and up the Trees Climbing, sat thicker then the snakie locks That curld MEGAERA: greedily they pluck'd The Frutage fair to sight, like that which grew Neer that bituminous Lake where SODOM flam'd; This more delusive, not the touch, but taste Deceav'd; they fondly thinking to allay Thir appetite with gust, instead of Fruit Chewd bitter Ashes, which th' offended taste VVith spattering noise rejected: oft they assayd, Hunger and thirst constraining, drugd as oft, VVith hatefullest disrelish writh'd thir jaws VVith foot and cinders fill'd; so oft they fell Into the same illusion, not as Man Whom they triumph'd once lapst. Thus were they plagu'd And worn with Famin, long and ceasless hiss, Till thir lost shape, permitted, they resum'd, Yearly enjoynd, some say, to undergo This annual humbling certain number'd days, To dash thir pride, and joy for Man seduc't. However some tradition they dispers'd Among the Heathen of thir purchase got, And Fabl'd how the Serpent, whom they calld OPHION with EURYNOME, the wide- Encroaching EVE perhaps, had first the rule Of high OLYMPUS, thence by SATURN driv'n And OPS, ere yet DICTAEAN JOVE was born. Mean while in Paradise the hellish pair Too soon arriv'd, SIN there in power before, Once actual, now in body, and to dwell Habitual habitant; behind her DEATH Close following pace for pace, not mounted yet On his pale Horse: to whom SIN thus began. Second of SATAN sprung, all conquering Death, What thinkst thou of our Empire now, though earnd With travail difficult, not better farr Then stil at Hels dark threshold to have sate watch, Unnam'd, undreaded, and thy self half starv'd? Whom thus the Sin-born Monster answerd soon. To mee, who with eternal Famin pine, Alike is Hell, or Paradise, or Heaven, There best, where most with ravin I may meet; Which here, though plenteous, all too little seems To stuff this Maw, this vast unhide-bound Corps. To whom th' incestuous Mother thus repli'd. Thou therefore on these Herbs, and Fruits, & Flours Feed first, on each Beast next, and Fish, and Fowle, No homely morsels, and whatever thing The Sithe of Time mowes down, devour unspar'd, Till I in Man residing through the Race, His thoughts, his looks, words, actions all infect, And season him thy last and sweetest prey. This said, they both betook them several wayes, Both to destroy, or unimmortal make All kinds, and for destruction to mature Sooner or later; which th' Almightie seeing, From his transcendent Seat the Saints among, To those bright Orders utterd thus his voice. See with what heat these Dogs of Hell advance To waste and havoc yonder VVorld, which I So fair and good created, and had still Kept in that state, had not the folly of Man Let in these wastful Furies, who impute Folly to mee, so doth the Prince of Hell And his Adherents, that with so much ease I suffer them to enter and possess A place so heav'nly, and conniving seem To gratifie my scornful Enemies, That laugh, as if transported with some fit Of Passion, I to them had quitted all, At random yeilded up to their misrule; And know not that I call'd and drew them thither My Hell-hounds, to lick up the draff and filth Which mans polluting Sin with taint hath shed On what was pure, till cramm'd and gorg'd, nigh burst With suckt and glutted offal, at one fling Of thy victorious Arm, well-pleasing Son, Both SIN, and DEATH, and yawning GRAVE at last Through CHAOS hurld, obstruct the mouth of Hell For ever, and seal up his ravenous Jawes. Then Heav'n and Earth renewd shall be made pure To sanctitie that shall receive no staine: Till then the Curse pronounc't on both precedes. Hee ended, and the heav'nly Audience loud Sung HALLELUIA, as the sound of Seas, Through multitude that sung: Just are thy ways, Righteous are thy Decrees on all thy Works; Who can extenuate thee? Next, to the Son, Destin'd restorer of Mankind, by whom New Heav'n and Earth shall to the Ages rise, Or down from Heav'n descend. Such was thir song, While the Creator calling forth by name His mightie Angels gave them several charge, As sorted best with present things. The Sun Had first his precept so to move, so shine, As might affect the Earth with cold and heat Scarce tollerable, and from the North to call Decrepit Winter, from the South to bring Solstitial summers heat. To the blanc Moone Her office they prescrib'd, to th' other five Thir planetarie motions and aspects In SEXTILE, SQUARE, and TRINE, and OPPOSITE, Of noxious efficacie, and when to joyne In Synod unbenigne, and taught the fixt Thir influence malignant when to showre, Which of them rising with the Sun, or falling, Should prove tempestuous: To the Winds they set Thir corners, when with bluster to confound Sea, Aire, and Shoar, the Thunder when to rowle With terror through the dark Aereal Hall. Some say he bid his Angels turne ascanse The Poles of Earth twice ten degrees and more From the Suns Axle; they with labour push'd Oblique the Centric Globe: Som say the Sun Was bid turn Reines from th' Equinoctial Rode Like distant breadth to TAURUS with the Seav'n ATLANTICK Sisters, and the SPARTAN Twins Up to the TROPIC Crab; thence down amaine By LEO and the VIRGIN and the SCALES, As deep as CAPRICORNE, to bring in change Of Seasons to each Clime; else had the Spring Perpetual smil'd on Earth with vernant Flours, Equal in Days and Nights, except to those Beyond the Polar Circles; to them Day Had unbenighted shon, while the low Sun To recompence his distance, in thir sight Had rounded still th' HORIZON, and not known Or East or West, which had forbid the Snow From cold ESTOTILAND, and South as farr Beneath MAGELLAN. At that tasted Fruit The Sun, as from THYESTEAN Banquet, turn'd His course intended; else how had the World Inhabited, though sinless, more then now, Avoided pinching cold and scorching heate? These changes in the Heav'ns, though slow, produc'd Like change on Sea and Land, sideral blast, Vapour, and Mist, and Exhalation hot, Corrupt and Pestilent: Now from the North Of NORUMBEGA, and the SAMOED shoar Bursting thir brazen Dungeon, armd with ice And snow and haile and stormie gust and flaw, BOREAS and CAECIAS and ARGESTES loud And THRASCIAS rend the Woods and Seas upturn; With adverse blast up-turns them from the South NOTUS and AFER black with thundrous Clouds From SERRALIONA; thwart of these as fierce Forth rush the LEVANT and the PONENT VVindes EURUS and ZEPHIR with thir lateral noise, SIROCCO, and LIBECCHIO. Thus began Outrage from liveless things; but Discord first Daughter of Sin, among th' irrational, Death introduc'd through fierce antipathie: Beast now with Beast gan war, & Fowle with Fowle, And Fish with Fish; to graze the Herb all leaving, Devourd each other; nor stood much in awe Of Man, but fled him, or with count'nance grim Glar'd on him passing: these were from without The growing miseries, which ADAM saw Alreadie in part, though hid in gloomiest shade, To sorrow abandond, but worse felt within, And in a troubl'd Sea of passion tost, Thus to disburd'n sought with sad complaint. O miserable of happie! is this the end Of this new glorious World, and mee so late The Glory of that Glory, who now becom Accurst of blessed, hide me from the face Of God, whom to behold was then my highth Of happiness: yet well, if here would end The miserie, I deserv'd it, and would beare My own deservings; but this will not serve; All that I eate or drink, or shall beget, Is propagated curse. O voice once heard Delightfully, ENCREASE AND MULTIPLY, Now death to heare! for what can I encrease Or multiplie, but curses on my head? Who of all Ages to succeed, but feeling The evil on him brought by me, will curse My Head, Ill fare our Ancestor impure, For this we may thank ADAM; but his thanks Shall be the execration; so besides Mine own that bide upon me, all from mee Shall with a fierce reflux on mee redound, On mee as on thir natural center light Heavie, though in thir place. O fleeting joyes Of Paradise, deare bought with lasting woes! Did I request thee, Maker, from my Clay To mould me Man, did I sollicite thee From darkness to promote me, or here place In this delicious Garden? as my Will Concurd not to my being, it were but right And equal to reduce me to my dust, Desirous to resigne, and render back All I receav'd, unable to performe Thy terms too hard, by which I was to hold The good I sought not. To the loss of that, Sufficient penaltie, why hast thou added The sense of endless woes? inexplicable Thy Justice seems; yet to say truth, too late, I thus contest; then should have been refusd Those terms whatever, when they were propos'd: Thou didst accept them; wilt thou enjoy the good, Then cavil the conditions? and though God Made thee without thy leave, what if thy Son Prove disobedient, and reprov'd, retort, Wherefore didst thou beget me? I sought it not: Wouldst thou admit for his contempt of thee That proud excuse? yet him not thy election, But Natural necessity begot. God made thee of choice his own, and of his own To serve him, thy reward was of his grace, Thy punishment then justly is at his Will. Be it so, for I submit, his doom is fair, That dust I am, and shall to dust returne: O welcom hour whenever! why delayes His hand to execute what his Decree Fixd on this day? why do I overlive, Why am I mockt with death, and length'nd out To deathless pain? how gladly would I meet Mortalitie my sentence, and be Earth Insensible, how glad would lay me down As in my Mothers lap? there I should rest And sleep secure; his dreadful voice no more Would Thunder in my ears, no fear of worse To mee and to my ofspring would torment me With cruel expectation. Yet one doubt Pursues me still, least all I cannot die, Least that pure breath of Life, the Spirit of Man Which God inspir'd, cannot together perish With this corporeal Clod; then in the Grave, Or in some other dismal place, who knows But I shall die a living Death? O thought Horrid, if true! yet why? it was but breath Of Life that sinn'd; what dies but what had life And sin? the Bodie properly hath neither. All of me then shall die: let this appease The doubt, since humane reach no further knows. For though the Lord of all be infinite, Is his wrauth also? be it, man is not so, But mortal doom'd. How can he exercise Wrath without end on Man whom Death must end? Can he make deathless Death? that were to make Strange contradiction, which to God himself Impossible is held, as Argument Of weakness, not of Power. Will he, draw out, For angers sake, finite to infinite In punisht man, to satisfie his rigour Satisfi'd never; that were to extend His Sentence beyond dust and Natures Law, By which all Causes else according still To the reception of thir matter act, Not to th' extent of thir own Spheare. But say That Death be not one stroak, as I suppos'd, Bereaving sense, but endless miserie From this day onward, which I feel begun Both in me, and without me, and so last To perpetuitie; Ay me, that fear Comes thundring back with dreadful revolution On my defensless head; both Death and I Am found Eternal, and incorporate both, Nor I on my part single, in mee all Posteritie stands curst: Fair Patrimonie That I must leave ye, Sons; O were I able To waste it all my self, and leave ye none! So disinherited how would ye bless Me now your Curse! Ah, why should all mankind For one mans fault thus guiltless be condemn'd, If guiltless? But from mee what can proceed, But all corrupt, both Mind and Will deprav'd, Not to do onely, but to will the same With me? how can they acquitted stand In sight of God? Him after all Disputes Forc't I absolve: all my evasions vain And reasonings, though through Mazes, lead me still But to my own conviction: first and last On mee, mee onely, as the sourse and spring Of all corruption, all the blame lights due; So might the wrauth, Fond wish! couldst thou support That burden heavier then the Earth to bear, Then all the world much heavier, though divided With that bad Woman? Thus what thou desir'st, And what thou fearst, alike destroyes all hope Of refuge, and concludes thee miserable Beyond all past example and future, To SATAN onely like both crime and doom. O Conscience, into what Abyss of fears And horrors hast thou driv'n me; out of which I find no way, from deep to deeper plung'd! Thus ADAM to himself lamented loud Through the still Night, now now, as ere man fell, Wholsom and cool, and mild, but with black Air Accompanied, with damps and dreadful gloom, Which to his evil Conscience represented All things with double terror: On the ground Outstretcht he lay, on the cold ground, and oft Curs'd his Creation, Death as oft accus'd Of tardie execution, since denounc't The day of his offence. Why comes not Death, Said hee, with one thrice acceptable stroke To end me? Shall Truth fail to keep her word, Justice Divine not hast'n to be just? But Death comes not at call, Justice Divine Mends not her slowest pace for prayers or cries. O Woods, O Fountains, Hillocks, Dales and Bowrs, VVith other echo farr I taught your Shades To answer, and resound farr other Song. VVhom thus afflicted when sad EVE beheld, Desolate where she sate, approaching nigh, Soft words to his fierce passion she assay'd: But her with stern regard he thus repell'd. Out of my sight, thou Serpent, that name best Befits thee with him leagu'd, thy self as false And hateful; nothing wants, but that thy shape, Like his, and colour Serpentine may shew Thy inward fraud, to warn all Creatures from thee Henceforth; least that too heav'nly form, pretended To hellish falshood, snare them. But for thee I had persisted happie, had not thy pride And wandring vanitie, when lest was safe, Rejected my forewarning, and disdain'd Not to be trusted, longing to be seen Though by the Devil himself, him overweening To over-reach, but with the Serpent meeting Fool'd and beguil'd, by him thou, I by thee, To trust thee from my side, imagin'd wise, Constant, mature, proof against all assaults, And understood not all was but a shew Rather then solid vertu, all but a Rib Crooked by nature, bent, as now appears, More to the part sinister from me drawn, Well if thrown out, as supernumerarie To my just number found. O why did God, Creator wise, that peopl'd highest Heav'n With Spirits Masculine, create at last This noveltie on Earth, this fair defect Of Nature, and not fill the World at once With Men as Angels without Feminine, Or find some other way to generate Mankind? this mischief had not then befall'n, And more that shall befall, innumerable Disturbances on Earth through Femal snares, And straight conjunction with this Sex: for either He never shall find out fit Mate, but such As some misfortune brings him, or mistake, Or whom he wishes most shall seldom gain Through her perverseness, but shall see her gaind By a farr worse, or if she love, withheld By Parents, or his happiest choice too late Shall meet, alreadie linkt and Wedlock-bound To a fell Adversarie, his hate or shame: Which infinite calamitie shall cause To humane life, and houshold peace confound. He added not, and from her turn'd, but EVE Not so repulst, with Tears that ceas'd not flowing, And tresses all disorderd, at his feet Fell humble, and imbracing them, besaught His peace, and thus proceeded in her plaint. Forsake me not thus, ADAM, witness Heav'n What love sincere, and reverence in my heart I beare thee, and unweeting have offended, Unhappilie deceav'd; thy suppliant I beg, and clasp thy knees; bereave me not, Whereon I live, thy gentle looks, thy aid, Thy counsel in this uttermost distress, My onely strength and stay: forlorn of thee, Whither shall I betake me, where subsist? While yet we live, scarse one short hour perhaps, Between us two let there be peace, both joyning, As joyn'd in injuries, one enmitie Against a Foe by doom express assign'd us, That cruel Serpent: On me exercise not Thy hatred for this miserie befall'n, On me already lost, mee then thy self More miserable; both have sin'd, but thou Against God onely, I against God and thee, And to the place of judgement will return, There with my cries importune Heaven, that all The sentence from thy head remov'd may light On me, sole cause to thee of all this woe, Mee mee onely just object of his ire. She ended weeping, and her lowlie plight, Immoveable till peace obtain'd from fault Acknowledg'd and deplor'd, in ADAM wraught Commiseration; soon his heart relented Towards her, his life so late and sole delight, Now at his feet submissive in distress, Creature so faire his reconcilement seeking, His counsel whom she had displeas'd, his aide; As one disarm'd, his anger all he lost, And thus with peaceful words uprais'd her soon. Unwarie, and too desirous, as before, So now of what thou knowst not, who desir'st The punishment all on thy self; alas, Beare thine own first, ill able to sustaine His full wrauth whose thou feelst as yet lest part, And my displeasure bearst so ill. If Prayers Could alter high Decrees, I to that place Would speed before thee, and be louder heard, That on my head all might be visited, Thy frailtie and infirmer Sex forgiv'n, To me committed and by me expos'd. But rise, let us no more contend, nor blame Each other, blam'd enough elsewhere, but strive In offices of Love, how we may light'n Each others burden in our share of woe; Since this days Death denounc't, if ought I see, Will prove no sudden, but a slow-pac't evill, A long days dying to augment our paine, And to our Seed (O hapless Seed!) deriv'd. To whom thus EVE, recovering heart, repli'd. ADAM, by sad experiment I know How little weight my words with thee can finde, Found so erroneous, thence by just event Found so unfortunate; nevertheless, Restor'd by thee, vile as I am, to place Of new acceptance, hopeful to regaine Thy Love, the sole contentment of my heart, Living or dying from thee I will not hide What thoughts in my unquiet brest are ris'n, Tending to som relief of our extremes, Or end, though sharp and sad, yet tolerable, As in our evils, and of easier choice. If care of our descent perplex us most, Which must be born to certain woe, devourd By Death at last, and miserable it is To be to others cause of misery, Our own begotten, and of our Loines to bring Into this cursed World a woful Race, That after wretched Life must be at last Food for so foule a Monster, in thy power It lies, yet ere Conception to prevent The Race unblest, to being yet unbegot. Childless thou art, Childless remaine: So Death shall be deceav'd his glut, and with us two Be forc'd to satisfie his Rav'nous Maw. But if thou judge it hard and difficult, Conversing, looking, loving, to abstain From Loves due Rites, Nuptial embraces sweet, And with desire to languish without hope, Before the present object languishing With like desire, which would be miserie And torment less then none of what we dread, Then both our selves and Seed at once to free From what we fear for both, let us make short, Let us seek Death, or hee not found, supply With our own hands his Office on our selves; Why stand we longer shivering under feares, That shew no end but Death, and have the power, Of many wayes to die the shortest choosing, Destruction with destruction to destroy. She ended heer, or vehement despaire Broke off the rest; so much of Death her thoughts Had entertaind, as di'd her Cheeks with pale. But ADAM with such counsel nothing sway'd, To better hopes his more attentive minde Labouring had rais'd, and thus to EVE repli'd. EVE, thy contempt of life and pleasure seems To argue in thee somthing more sublime And excellent then what thy minde contemnes; But self-destruction therefore saught, refutes That excellence thought in thee, and implies, Not thy contempt, but anguish and regret For loss of life and pleasure overlov'd. Or if thou covet death, as utmost end Of miserie, so thinking to evade The penaltie pronounc't, doubt not but God Hath wiselier arm'd his vengeful ire then so To be forestall'd; much more I fear least Death So snatcht will not exempt us from the paine We are by doom to pay; rather such acts Of contumacie will provoke the highest To make death in us live: Then let us seek Som safer resolution, which methinks I have in view, calling to minde with heed Part of our Sentence, that thy Seed shall bruise The Serpents head; piteous amends, unless Be meant, whom I conjecture, our grand Foe SATAN, who in the Serpent hath contriv'd Against us this deceit: to crush his head Would be revenge indeed; which will be lost By death brought on our selves, or childless days Resolv'd, as thou proposest; so our Foe Shall scape his punishment ordain'd, and wee Instead shall double ours upon our heads. No more be mention'd then of violence Against our selves, and wilful barrenness, That cuts us off from hope, and savours onely Rancor and pride, impatience and despite, Reluctance against God and his just yoke Laid on our Necks. Remember with what mild And gracious temper he both heard and judg'd Without wrauth or reviling; wee expected Immediate dissolution, which we thought Was meant by Death that day, when lo, to thee Pains onely in Child-bearing were foretold, And bringing forth, soon recompenc't with joy, Fruit of thy Womb: On mee the Curse aslope Glanc'd on the ground, with labour I must earne My bread; what harm? Idleness had bin worse; My labour will sustain me; and least Cold Or Heat should injure us, his timely care Hath unbesaught provided, and his hands Cloath'd us unworthie, pitying while he judg'd; How much more, if we pray him, will his ear Be open, and his heart to pitie incline, And teach us further by what means to shun Th' inclement Seasons, Rain, Ice, Hail and Snow, Which now the Skie with various Face begins To shew us in this Mountain, while the Winds Blow moist and keen, shattering the graceful locks Of these fair spreading Trees; which bids us seek Som better shroud, som better warmth to cherish Our Limbs benumm'd, ere this diurnal Starr Leave cold the Night, how we his gather'd beams Reflected, may with matter sere foment, Or by collision of two bodies grinde The Air attrite to Fire, as late the Clouds Justling or pusht with Winds rude in thir shock Tine the slant Lightning, whose thwart flame driv'n down Kindles the gummie bark of Firr or Pine, And sends a comfortable heat from farr, Which might supplie the Sun: such Fire to use, And what may else be remedie or cure To evils which our own misdeeds have wrought, Hee will instruct us praying, and of Grace Beseeching him, so as we need not fear To pass commodiously this life, sustain'd By him with many comforts, till we end In dust, our final rest and native home. What better can we do, then to the place Repairing where he judg'd us, prostrate fall Before him reverent, and there confess Humbly our faults, and pardon beg, with tears VVatering the ground, and with our sighs the Air Frequenting, sent from hearts contrite, in sign Of sorrow unfeign'd, and humiliation meek. Undoubtedly he will relent and turn From his displeasure; in whose look serene, VVhen angry most he seem'd and most severe, VVhat else but favor, grace, and mercie shon? So spake our Father penitent, nor EVE Felt less remorse: they forthwith to the place Repairing where he judg'd them prostrate fell Before him reverent, and both confess'd Humbly thir faults, and pardon beg'd, with tears VVatering the ground, and with thir sighs the Air Frequenting, sent from hearts contrite, in sign Of sorrow unfeign'd, and humiliation meek. THE END OF THE NINTH BOOK. PARADISE LOST. BOOK X. Thus they in lowliest plight repentant stood Praying, for from the Mercie-seat above Prevenient Grace descending had remov'd The stonie from thir hearts, and made new flesh Regenerat grow instead, that sighs now breath'd Unutterable, which the Spirit of prayer Inspir'd, and wing'd for Heav'n with speedier flight Then loudest Oratorie: yet thir port Not of mean suiters, nor important less Seem'd thir Petition, then when th' ancient Pair In Fables old, less ancient yet then these, DEUCALION and chaste PYRRHA to restore The Race of Mankind drownd, before the Shrine Of THEMIS stood devout. To Heav'n thir prayers Flew up, nor missed the way, by envious windes Blow'n vagabond or frustrate: in they passd Dimentionless through Heav'nly dores; then clad With incense, where the Golden Altar fum'd, By thir great Intercessor, came in sight Before the Fathers Throne: Them the glad Son Presenting, thus to intercede began. See Father, what first fruits on Earth are sprung From thy implanted Grace in Man, these Sighs And Prayers, which in this Golden Censer, mixt With Incense, I thy Priest before thee bring, Fruits of more pleasing savour from thy seed Sow'n with contrition in his heart, then those Which his own hand manuring all the Trees Of Paradise could have produc't, ere fall'n From innocence. Now therefore bend thine eare To supplication, heare his sighs though mute; Unskilful with what words to pray, let mee Interpret for him, mee his Advocate And propitiation, all his works on mee Good or not good ingraft, my Merit those Shall perfet, and for these my Death shall pay. Accept me, and in mee from these receave The smell of peace toward Mankinde, let him live Before thee reconcil'd, at least his days Numberd, though sad, till Death, his doom (which I To mitigate thus plead, not to reverse) To better life shall yeeld him, where with mee All my redeemd may dwell in joy and bliss, Made one with me as I with thee am one. To whom the Father, without Cloud, serene. All thy request for Man, accepted Son, Obtain, all thy request was my Decree: But longer in that Paradise to dwell, The Law I gave to Nature him forbids: Those pure immortal Elements that know No gross, no unharmoneous mixture foule, Eject him tainted now, and purge him off As a distemper, gross to aire as gross, And mortal food, as may dispose him best For dissolution wrought by Sin, that first Distemperd all things, and of incorrupt Corrupted. I at first with two fair gifts Created him endowd, with Happiness And Immortalitie: that fondly lost, This other serv'd but to eternize woe; Till I provided Death; so Death becomes His final remedie, and after Life Tri'd in sharp tribulation, and refin'd By Faith and faithful works, to second Life, Wak't in the renovation of the just, Resignes him up with Heav'n and Earth renewd. But let us call to Synod all the Blest Through Heav'ns wide bounds; from them I will not hide My judgments, how with Mankind I proceed, As how with peccant Angels late they saw; And in thir state, though firm, stood more confirmd. He ended, and the Son gave signal high To the bright Minister that watchd, hee blew His Trumpet, heard in OREB since perhaps When God descended, and perhaps once more To sound at general Doom. Th' Angelic blast Filld all the Regions: from thir blissful Bowrs Of AMARANTIN Shade, Fountain or Spring, By the waters of Life, where ere they sate In fellowships of joy: the Sons of Light Hasted, resorting to the Summons high, And took thir Seats; till from his Throne supream Th' Almighty thus pronounced his sovran Will. O Sons, like one of us Man is become To know both Good and Evil, since his taste Of that defended Fruit; but let him boast His knowledge of Good lost, and Evil got, Happier, had it suffic'd him to have known Good by it self, and Evil not at all. He sorrows now, repents, and prayes contrite, My motions in him, longer then they move, His heart I know, how variable and vain Self-left. Least therefore his now bolder hand Reach also of the Tree of Life, and eat, And live for ever, dream at least to live Forever, to remove him I decree, And send him from the Garden forth to Till The Ground whence he was taken, fitter soile. MICHAEL, this my behest have thou in charge, Take to thee from among the Cherubim Thy choice of flaming Warriours, least the Fiend Or in behalf of Man, or to invade Vacant possession som new trouble raise: Hast thee, and from the Paradise of God Without remorse drive out the sinful Pair, From hallowd ground th' unholie, and denounce To them and to thir Progenie from thence Perpetual banishment. Yet least they faint At the sad Sentence rigorously urg'd, For I behold them soft'nd and with tears Bewailing thir excess, all terror hide. If patiently thy bidding they obey, Dismiss them not disconsolate; reveale To ADAM what shall come in future dayes, As I shall thee enlighten, intermix My Cov'nant in the Womans seed renewd; So send them forth, though sorrowing, yet in peace: And on the East side of the Garden place, Where entrance up from EDEN easiest climbes, Cherubic watch, and of a Sword the flame Wide waving, all approach farr off to fright, And guard all passage to the Tree of Life: Least Paradise a receptacle prove To Spirits foule, and all my Trees thir prey, With whose stol'n Fruit Man once more to delude. He ceas'd; and th' Archangelic Power prepar'd For swift descent, with him the Cohort bright Of watchful Cherubim; four faces each Had, like a double JANUS, all thir shape Spangl'd with eyes more numerous then those Of ARGUS, and more wakeful then to drouze, Charm'd with ARCADIAN Pipe, the Pastoral Reed Of HERMES, or his opiate Rod. Meanwhile To resalute the World with sacred Light LEUCOTHEA wak'd, and with fresh dews imbalmd The Earth, when ADAM and first Matron EVE Had ended now thir Orisons, and found, Strength added from above, new hope to spring Out of despaire, joy, but with fear yet linkt; Which thus to EVE his welcome words renewd. EVE, easily may Faith admit, that all The good which we enjoy, from Heav'n descends But that from us ought should ascend to Heav'n So prevalent as to concerne the mind Of God high blest, or to incline his will, Hard to belief may seem; yet this will Prayer, Or one short sigh of humane breath, up-borne Ev'n to the Seat of God. For since I saught By Prayer th' offended Deitie to appease, Kneel'd and before him humbl'd all my heart, Methought I saw him placable and mild, Bending his eare; perswasion in me grew That I was heard with favour; peace returnd Home to my brest, and to my memorie His promise, that thy Seed shall bruise our Foe; Which then not minded in dismay, yet now Assures me that the bitterness of death Is past, and we shall live. Whence Haile to thee, EVE rightly call'd, Mother of all Mankind, Mother of all things living, since by thee Man is to live, and all things live for Man. To whom thus EVE with sad demeanour meek. Ill worthie I such title should belong To me transgressour, who for thee ordaind A help, became thy snare; to mee reproach Rather belongs, distrust and all dispraise: But infinite in pardon was my Judge, That I who first brought Death on all, am grac't The sourse of life; next favourable thou, Who highly thus to entitle me voutsaf't, Farr other name deserving. But the Field To labour calls us now with sweat impos'd, Though after sleepless Night; for see the Morn, All unconcern'd with our unrest, begins Her rosie progress smiling; let us forth, I never from thy side henceforth to stray, Wherere our days work lies, though now enjoind Laborious, till day droop; while here we dwell, What can be toilsom in these pleasant Walkes? Here let us live, though in fall'n state, content. So spake, so wish'd much-humbl'd EVE, but Fate Subscrib'd not; Nature first gave Signs, imprest On Bird, Beast, Aire, Aire suddenly eclips'd After short blush of Morn; nigh in her sight The Bird of JOVE, stoopt from his aerie tour, Two Birds of gayest plume before him drove: Down from a Hill the Beast that reigns in Woods, First Hunter then, pursu'd a gentle brace, Goodliest of all the Forrest, Hart and Hinde; Direct to th' Eastern Gate was bent thir flight. ADAM observ'd, and with his Eye the chase Pursuing, not unmov'd to EVE thus spake. O EVE, some furder change awaits us nigh, Which Heav'n by these mute signs in Nature shews Forerunners of his purpose, or to warn Us haply too secure of our discharge From penaltie, because from death releast Some days; how long, and what till then our life, Who knows, or more then this, that we are dust, And thither must return and be no more. VVhy else this double object in our sight Of flight pursu'd in th' Air and ore the ground One way the self-same hour? why in the East Darkness ere Dayes mid-course, and Morning light More orient in yon VVestern Cloud that draws O're the blew Firmament a radiant white, And slow descends, with somthing heav'nly fraught. He err'd not, for by this the heav'nly Bands Down from a Skie of Jasper lighted now In Paradise, and on a Hill made alt, A glorious Apparition, had not doubt And carnal fear that day dimm'd ADAMS eye. Not that more glorious, when the Angels met JACOB in MAHANAIM, where he saw The field Pavilion'd with his Guardians bright; Nor that which on the flaming Mount appeerd In DOTHAN, cover'd with a Camp of Fire, Against the SYRIAN King, who to surprize One man, Assassin-like had levied Warr, Warr unproclam'd. The Princely Hierarch In thir bright stand, there left his Powers to seise Possession of the Garden; hee alone, To finde where ADAM shelterd, took his way, Not unperceav'd of ADAM, who to EVE, While the great Visitant approachd, thus spake. EVE, now expect great tidings, which perhaps Of us will soon determin, or impose New Laws to be observ'd; for I descrie From yonder blazing Cloud that veils the Hill One of the heav'nly Host, and by his Gate None of the meanest, some great Potentate Or of the Thrones above, such Majestie Invests him coming; yet not terrible, That I should fear, nor sociably mild, As RAPHAEL, that I should much confide, But solemn and sublime, whom not to offend, With reverence I must meet, and thou retire. He ended; and th' Arch-Angel soon drew nigh, Not in his shape Celestial, but as Man Clad to meet Man; over his lucid Armes A militarie Vest of purple flowd Livelier then MELIBOEAN, or the graine Of SARRA, worn by Kings and Hero's old In time of Truce; IRIS had dipt the wooff; His starrie Helme unbuckl'd shew'd him prime In Manhood where Youth ended; by his side As in a glistering ZODIAC hung the Sword, Satans dire dread, and in his hand the Spear. ADAM bowd low, hee Kingly from his State Inclin'd not, but his coming thus declar'd. ADAM, Heav'ns high behest no Preface needs: Sufficient that thy Prayers are heard, and Death, Then due by sentence when thou didst transgress, Defeated of his seisure many dayes Giv'n thee of Grace, wherein thou may'st repent, And one bad act with many deeds well done Mayst cover: well may then thy Lord appeas'd Redeem thee quite from Deaths rapacious claimes; But longer in this Paradise to dwell Permits not; to remove thee I am come, And send thee from the Garden forth to till The ground whence thou wast tak'n, fitter Soile. He added not, for ADAM at the newes Heart-strook with chilling gripe of sorrow stood, That all his senses bound; EVE, who unseen Yet all had heard, with audible lament Discover'd soon the place of her retire. O unexpected stroke, worse then of Death! Must I thus leave thee Paradise? thus leave Thee Native Soile, these happie Walks and Shades, Fit haunt of Gods? where I had hope to spend, Quiet though sad, the respit of that day That must be mortal to us both. O flours, That never will in other Climate grow, My early visitation, and my last At Eev'n, which I bred up with tender hand From the first op'ning bud, and gave ye Names, Who now shall reare ye to the Sun, or ranke Your Tribes, and water from th' ambrosial Fount? Thee lastly nuptial Bowre, by mee adornd With what to sight or smell was sweet; from thee How shall I part, and whither wander down Into a lower World, to this obscure And wilde, how shall we breath in other Aire Less pure, accustomd to immortal Fruits? Whom thus the Angel interrupted milde. Lament not EVE, but patiently resigne What justly thou hast lost; nor set thy heart, Thus over fond, on that which is not thine; Thy going is not lonely, with thee goes Thy Husband, him to follow thou art bound; Where he abides, think there thy native soile. ADAM by this from the cold sudden damp Recovering, and his scatterd spirits returnd, To MICHAEL thus his humble words addressd. Celestial, whether among the Thrones, or nam'd Of them the Highest, for such of shape may seem Prince above Princes, gently hast thou tould Thy message, which might else in telling wound, And in performing end us; what besides Of sorrow and dejection and despair Our frailtie can sustain, thy tidings bring, Departure from this happy place, our sweet Recess, and onely consolation left Familiar to our eyes, all places else Inhospitable appeer and desolate, Nor knowing us nor known: and if by prayer Incessant I could hope to change the will Of him who all things can, I would not cease To wearie him with my assiduous cries: But prayer against his absolute Decree No more availes then breath against the winde, Blown stifling back on him that breaths it forth: Therefore to his great bidding I submit. This most afflicts me, that departing hence, As from his face I shall be hid, deprivd His blessed count'nance; here I could frequent, With worship, place by place where he voutsaf'd Presence Divine, and to my Sons relate; On this Mount he appeerd, under this Tree Stood visible, among these Pines his voice I heard, here with him at this Fountain talk'd: So many grateful Altars I would reare Of grassie Terfe, and pile up every Stone Of lustre from the brook, in memorie, Or monument to Ages, and thereon Offer sweet smelling Gumms & Fruits and Flours: In yonder nether World where shall I seek His bright appearances, or footstep trace? For though I fled him angrie, yet recall'd To life prolongd and promisd Race, I now Gladly behold though but his utmost skirts Of glory, and farr off his steps adore. To whom thus MICHAEL with regard benigne. ADAM, thou know'st Heav'n his, and all the Earth Not this Rock onely; his Omnipresence fills Land, Sea, and Aire, and every kinde that lives, Fomented by his virtual power and warmd: All th' Earth he gave thee to possess and rule, No despicable gift; surmise not then His presence to these narrow bounds confin'd Of Paradise or EDEN: this had been Perhaps thy Capital Seate, from whence had spred All generations, and had hither come From all the ends of th' Earth, to celebrate And reverence thee thir great Progenitor. But this praeeminence thou hast lost, brought down To dwell on eeven ground now with thy Sons: Yet doubt not but in Vallie and in Plaine God is as here, and will be found alike Present, and of his presence many a signe Still following thee, still compassing thee round With goodness and paternal Love, his Face Express, and of his steps the track Divine. Which that thou mayst beleeve, and be confirmd, Ere thou from hence depart, know I am sent To shew thee what shall come in future dayes To thee and to thy Ofspring; good with bad Expect to hear, supernal Grace contending With sinfulness of Men; thereby to learn True patience, and to temper joy with fear And pious sorrow, equally enur'd By moderation either state to beare, Prosperous or adverse: so shalt thou lead Safest thy life, and best prepar'd endure Thy mortal passage when it comes. Ascend This Hill; let EVE (for I have drencht her eyes) Here sleep below while thou to foresight wak'st, As once thou slepst, while Shee to life was formd. To whom thus ADAM gratefully repli'd. Ascend, I follow thee, safe Guide, the path Thou lead'st me, and to the hand of Heav'n submit, However chast'ning, to the evil turne My obvious breast, arming to overcom By suffering, and earne rest from labour won, If so I may attain. So both ascend In the Visions of God: It was a Hill Of Paradise the highest, from whose top The Hemisphere of Earth in cleerest Ken Stretcht out to amplest reach of prospect lay. Not higher that Hill nor wider looking round, Whereon for different cause the Tempter set Our second ADAM in the Wilderness, To shew him all Earths Kingdomes and thir Glory. His Eye might there command wherever stood City of old or modern Fame, the Seat Of mightiest Empire, from the destind Walls Of CAMBALU, seat of CATHAIAN CAN And SAMARCHAND by OXUS, TEMIRS Throne, To PAQUIN of SINAEAN Kings, and thence To AGRA and LAHOR of great MOGUL Down to the golden CHERSONESE, or where The PERSIAN in ECBATAN sate, or since In HISPAHAN, or where the RUSSIAN KSAR In MOSCO, or the Sultan in BIZANCE, TURCHESTAN-born; nor could his eye not ken Th' Empire of NEGUS to his utmost Port ERCOCO and the less Maritine Kings MOMBAZA, and QUILOA, and MELIND, And SOFALA thought OPHIR, to the Realme Of CONGO, and ANGOLA fardest South; Or thence from NIGER Flood to ATLAS Mount The Kingdoms of ALMANSOR, FEZ, and SUS, MAROCCO and ALGIERS, and TREMISEN; On EUROPE thence, and where ROME was to sway The VVorld: in Spirit perhaps he also saw Rich MEXICO the seat of MOTEZUME, And CUSCO in PERU, the richer seat Of ATABALIPA, and yet unspoil'd GUIANA, whose great Citie GERYONS Sons Call EL DORADO: but to nobler sights MICHAEL from ADAMS eyes the Filme remov'd VVhich that false Fruit that promis'd clearer sight Had bred; then purg'd with Euphrasie and Rue The visual Nerve, for he had much to see; And from the VVell of Life three drops instill'd. So deep the power of these Ingredients pierc'd, Eevn to the inmost seat of mental sight, That ADAM now enforc't to close his eyes, Sunk down and all his Spirits became intranst: But him the gentle Angel by the hand Soon rais'd, and his attention thus recall'd. ADAM, now ope thine eyes, and first behold Th' effects which thy original crime hath wrought In some to spring from thee, who never touch'd Th' excepted Tree, nor with the Snake conspir'd, Nor sinn'd thy sin, yet from that sin derive Corruption to bring forth more violent deeds. His eyes he op'nd, and beheld a field, Part arable and tilth, whereon were Sheaves New reapt, the other part sheep-walks and foulds; Ith' midst an Altar as the Land-mark stood Rustic, of grassie sord; thither anon A sweatie Reaper from his Tillage brought First Fruits, the green Eare, and the yellow Sheaf, Uncull'd, as came to hand; a Shepherd next More meek came with the Firstlings of his Flock Choicest and best; then sacrificing, laid The Inwards and thir Fat, with Incense strew'd, On the cleft Wood, and all due Rites perform'd. His Offring soon propitious Fire from Heav'n Consum'd with nimble glance, and grateful steame; The others not, for his was not sincere; Whereat hee inlie rag'd, and as they talk'd, Smote him into the Midriff with a stone That beat out life; he fell, and deadly pale Groand out his Soul with gushing bloud effus'd. Much at that sight was ADAM in his heart Dismai'd, and thus in haste to th' Angel cri'd. O Teacher, some great mischief hath befall'n To that meek man, who well had sacrific'd; Is Pietie thus and pure Devotion paid? T' whom MICHAEL thus, hee also mov'd, repli'd. These two are Brethren, ADAM, and to come Out of thy loyns; th' unjust the just hath slain, For envie that his Brothers Offering found From Heav'n acceptance; but the bloodie Fact Will be aveng'd, and th' others Faith approv'd Loose no reward, though here thou see him die, Rowling in dust and gore. To which our Sire. Alas, both for the deed and for the cause! But have I now seen Death? Is this the way I must return to native dust? O sight Of terrour, foul and ugly to behold, Horrid to think, how horrible to feel! To whom thus MICHAEL. Death thou hast seen In his first shape on man; but many shapes Of Death, and many are the wayes that lead To his grim Cave, all dismal; yet to sense More terrible at th' entrance then within. Some, as thou saw'st, by violent stroke shall die, By Fire, Flood, Famin, by Intemperance more In Meats and Drinks, which on the Earth shal bring Diseases dire, of which a monstrous crew Before thee shall appear; that thou mayst know What miserie th' inabstinence of EVE Shall bring on men. Immediately a place Before his eyes appeard, sad, noysom, dark, A Lazar-house it seemd, wherein were laid Numbers of all diseas'd, all maladies Of gastly Spasm, or racking torture, qualmes Of heart-sick Agonie, all feavorous kinds, Convulsions, Epilepsies, fierce Catarrhs, Intestin Stone and Ulcer, Colic pangs, Dropsies, and Asthma's, and Joint-racking Rheums. Dire was the tossing, deep the groans, despair Tended the sick busiest from Couch to Couch; And over them triumphant Death his Dart Shook, but delaid to strike, though oft invok't With vows, as thir chief good, and final hope. Sight so deform what heart of Rock could long Drie-ey'd behold? ADAM could not, but wept, Though not of Woman born; compassion quell'd His best of Man, and gave him up to tears A space, till firmer thoughts restraind excess, And scarce recovering words his plaint renew'd. O miserable Mankind, to what fall Degraded, to what wretched state reserv'd? Better end heer unborn. Why is life giv'n To be thus wrested from us? rather why Obtruded on us thus? who if we knew What we receive, would either not accept Life offer'd, or soon beg to lay it down, Glad to be so dismist in peace. Can thus Th' Image of God in man created once So goodly and erect, though faultie since, To such unsightly sufferings be debas't Under inhuman pains? Why should not Man, Retaining still Divine similitude In part, from such deformities be free, And for his Makers Image sake exempt? Thir Makers Image, answerd MICHAEL, then Forsook them, when themselves they villifi'd To serve ungovern'd appetite, and took His Image whom they serv'd, a brutish vice, Inductive mainly to the sin of EVE. Therefore so abject is thir punishment, Disfiguring not Gods likeness, but thir own, Or if his likeness, by themselves defac't While they pervert pure Natures healthful rules To loathsom sickness, worthily, since they Gods Image did not reverence in themselves. I yeild it just, said ADAM, and submit. But is there yet no other way, besides These painful passages, how we may come To Death, and mix with our connatural dust? There is, said MICHAEL, if thou well observe The rule of not too much, by temperance taught In what thou eatst and drinkst, seeking from thence Due nourishment, not gluttonous delight, Till many years over thy head return: So maist thou live, till like ripe Fruit thou drop Into thy Mothers lap, or be with ease Gatherd, not harshly pluckt, for death mature: This is old age; but then thou must outlive Thy youth, thy strength, thy beauty, which will change To witherd weak & gray; thy Senses then Obtuse, all taste of pleasure must forgoe, To what thou hast, and for the Aire of youth Hopeful and cheerful, in thy blood will reigne A melancholly damp of cold and dry To waigh thy spirits down, and last consume The Balme of Life. To whom our Ancestor. Henceforth I flie not Death, nor would prolong Life much, bent rather how I may be quit Fairest and easiest of this combrous charge, Which I must keep till my appointed day Of rendring up. MICHAEL to him repli'd. Nor love thy Life, nor hate; but what thou livst Live well, how long or short permit to Heav'n: And now prepare thee for another sight. He lookd and saw a spacious Plaine, whereon Were Tents of various hue; by some were herds Of Cattel grazing: others, whence the sound Of Instruments that made melodious chime Was heard, of Harp and Organ; and who moovd Thir stops and chords was seen: his volant touch Instinct through all proportions low and high Fled and pursu'd transverse the resonant fugue. In other part stood one who at the Forge Labouring, two massie clods of Iron and Brass Had melted (whether found where casual fire Had wasted woods on Mountain or in Vale, Down to the veins of Earth, thence gliding hot To som Caves mouth, or whether washt by stream From underground) the liquid Ore he dreind Into fit moulds prepar'd; from which he formd First his own Tooles; then, what might else be wrought Fulfil or grav'n in mettle. After these, But on the hether side a different sort From the high neighbouring Hills, which was thir Seat, Down to the Plain descended: by thir guise Just men they seemd, and all thir study bent To worship God aright, and know his works Not hid, nor those things lost which might preserve Freedom and Peace to men: they on the Plain Long had not walkt, when from the Tents behold A Beavie of fair Women, richly gay In Gems and wanton dress; to the Harp they sung Soft amorous Ditties, and in dance came on: The Men though grave, ey'd them, and let thir eyes Rove without rein, till in the amorous Net Fast caught, they lik'd, and each his liking chose; And now of love they treat till th' Eevning Star Loves Harbinger appeerd; then all in heat They light the Nuptial Torch, and bid invoke Hymen, then first to marriage Rites invok't; With Feast and Musick all the Tents resound. Such happy interview and fair event Of love & youth not lost, Songs, Garlands, Flours, And charming Symphonies attach'd the heart Of ADAM, soon enclin'd to admit delight, The bent of Nature; which he thus express'd. True opener of mine eyes, prime Angel blest, Much better seems this Vision, and more hope Of peaceful dayes portends, then those two past; Those were of hate and death, or pain much worse, Here Nature seems fulfilld in all her ends. To whom thus MICHAEL. Judg not what is best By pleasure, though to Nature seeming meet, Created, as thou art, to nobler end Holie and pure, conformitie divine. Those Tents thou sawst so pleasant, were the Tents Of wickedness, wherein shall dwell his Race Who slew his Brother; studious they appere Of Arts that polish Life, Inventers rare, Unmindful of thir Maker, though his Spirit Taught them, but they his gifts acknowledg'd none. Yet they a beauteous ofspring shall beget; For that fair femal Troop thou sawst, that seemd Of Goddesses, so blithe, so smooth, so gay, Yet empty of all good wherein consists Womans domestic honour and chief praise; Bred onely and completed to the taste Of lustful apperence, to sing, to dance, To dress, and troule the Tongue, and roule the Eye. To these that sober Race of Men, whose lives Religious titl'd them the Sons of God, Shall yeild up all thir vertue, all thir fame Ignobly, to the trains and to the smiles Of these fair Atheists, and now swim in joy, (Erelong to swim at larg) and laugh; for which The world erelong a world of tears must weepe. To whom thus ADAM of short joy bereft. O pittie and shame, that they who to live well Enterd so faire, should turn aside to tread Paths indirect, or in the mid way faint! But still I see the tenor of Mans woe Holds on the same, from Woman to begin. From Mans effeminate slackness it begins, Said th' Angel, who should better hold his place By wisdome, and superiour gifts receavd. But now prepare thee for another Scene. He lookd and saw wide Territorie spred Before him, Towns, and rural works between, Cities of Men with lofty Gates and Towrs, Concours in Arms, fierce Faces threatning Warr, Giants of mightie Bone, and bould emprise; Part wield thir Arms, part courb the foaming Steed, Single or in Array of Battel rang'd Both Horse and Foot, nor idely mustring stood; One way a Band select from forage drives A herd of Beeves, faire Oxen and faire Kine From a fat Meddow ground; or fleecy Flock, Ewes and thir bleating Lambs over the Plaine, Thir Bootie; scarce with Life the Shepherds flye, But call in aide, which tacks a bloody Fray; With cruel Tournament the Squadrons joine; Where Cattel pastur'd late, now scatterd lies With Carcasses and Arms th' ensanguind Field Deserted: Others to a Citie strong Lay Siege, encampt; by Batterie, Scale, and Mine, Assaulting; others from the Wall defend With Dart and Jav'lin, Stones and sulfurous Fire; On each hand slaughter and gigantic deeds. In other part the scepter'd Haralds call To Council in the Citie Gates: anon Grey-headed men and grave, with Warriours mixt, Assemble, and Harangues are heard, but soon In factious opposition, till at last Of middle Age one rising, eminent In wise deport, spake much of Right and Wrong, Of Justice, of Religion, Truth and Peace, And Judgement from above: him old and young Exploded, and had seiz'd with violent hands, Had not a Cloud descending snatch'd him thence Unseen amid the throng: so violence Proceeded, and Oppression, and Sword-Law Through all the Plain, and refuge none was found. ADAM was all in tears, and to his guide Lamenting turnd full sad; O what are these, Deaths Ministers, not Men, who thus deal Death Inhumanly to men, and multiply Ten thousand fould the sin of him who slew His Brother; for of whom such massacher Make they but of thir Brethren, men of men? But who was that Just Man, whom had not Heav'n Rescu'd, had in his Righteousness bin lost? To whom thus MICHAEL; These are the product Of those ill-mated Marriages thou saw'st; Where good with bad were matcht, who of themselves Abhor to joyn; and by imprudence mixt, Produce prodigious Births of bodie or mind. Such were these Giants, men of high renown; For in those dayes Might onely shall be admir'd, And Valour and Heroic Vertu call'd; To overcome in Battel, and subdue Nations, and bring home spoils with infinite Man-slaughter, shall be held the highest pitch Of human Glorie, and for Glorie done Of triumph, to be styl'd great Conquerours, Patrons of Mankind, Gods, and Sons of Gods, Destroyers rightlier call'd and Plagues of men. Thus Fame shall be achiev'd, renown on Earth, And what most merits fame in silence hid. But hee the seventh from thee, whom thou beheldst The onely righteous in a World perverse, And therefore hated, therefore so beset With Foes for daring single to be just, And utter odious Truth, that God would come To judge them with his Saints: Him the most High Rapt in a balmie Cloud with winged Steeds Did, as thou sawst, receave, to walk with God High in Salvation and the Climes of bliss, Exempt from Death; to shew thee what reward Awaits the good, the rest what punishment; Which now direct thine eyes and soon behold. He look'd, & saw the face of things quite chang'd; The brazen Throat of Warr had ceast to roar, All now was turn'd to jollitie and game, To luxurie and riot, feast and dance, Marrying or prostituting, as befell, Rape or Adulterie, where passing faire Allurd them; thence from Cups to civil Broiles. At length a Reverend Sire among them came, And of thir doings great dislike declar'd, And testifi'd against thir wayes; hee oft Frequented thir Assemblies, whereso met, Triumphs or Festivals, and to them preachd Conversion and Repentance, as to Souls In prison under Judgements imminent: But all in vain: which when he saw, he ceas'd Contending, and remov'd his Tents farr off; Then from the Mountain hewing Timber tall, Began to build a Vessel of huge bulk, Measur'd by Cubit, length, & breadth, and highth, Smeard round with Pitch, and in the side a dore Contriv'd, and of provisions laid in large For Man and Beast: when loe a wonder strange! Of everie Beast, and Bird, and Insect small Came seavens, and pairs, and enterd in, as taught Thir order; last the Sire, and his three Sons With thir four Wives, and God made fast the dore. Meanwhile the Southwind rose, & with black wings Wide hovering, all the Clouds together drove From under Heav'n; the Hills to their supplie Vapour, and Exhalation dusk and moist, Sent up amain; and now the thick'nd Skie Like a dark Ceeling stood; down rush'd the Rain Impetuous, and continu'd till the Earth No more was seen; the floating Vessel swum Uplifted; and secure with beaked prow Rode tilting o're the Waves, all dwellings else Flood overwhelmd, and them with all thir pomp Deep under water rould; Sea cover'd Sea, Sea without shoar; and in thir Palaces Where luxurie late reign'd, Sea-monsters whelp'd And stabl'd; of Mankind, so numerous late, All left, in one small bottom swum imbark't. How didst thou grieve then, ADAM, to behold The end of all thy Ofspring, end so sad, Depopulation; thee another Floud, Of tears and sorrow a Floud thee also drown'd, And sunk thee as thy Sons; till gently reard By th' Angel, on thy feet thou stoodst at last, Though comfortless, as when a Father mourns His Childern, all in view destroyd at once; And scarce to th' Angel utterdst thus thy plaint. O Visions ill foreseen! better had I Liv'd ignorant of future, so had borne My part of evil onely, each dayes lot Anough to bear; those now, that were dispenst The burd'n of many Ages, on me light At once, by my foreknowledge gaining Birth Abortive, to torment me ere thir being, With thought that they must be. Let no man seek Henceforth to be foretold what shall befall Him or his Childern, evil he may be sure, Which neither his foreknowing can prevent, And hee the future evil shall no less In apprehension then in substance feel Grievous to bear: but that care now is past, Man is not whom to warne: those few escap't Famin and anguish will at last consume Wandring that watrie Desert: I had hope When violence was ceas't, and Warr on Earth, All would have then gon well, peace would have crownd With length of happy days the race of man; But I was farr deceav'd; for now I see Peace to corrupt no less then Warr to waste. How comes it thus? unfould, Celestial Guide, And whether here the Race of man will end. To whom thus MICHAEL. Those whom last thou sawst In triumph and luxurious wealth, are they First seen in acts of prowess eminent And great exploits, but of true vertu void; Who having spilt much blood, and don much waste Subduing Nations, and achievd thereby Fame in the World, high titles, and rich prey, Shall change thir course to pleasure, ease, and sloth, Surfet, and lust, till wantonness and pride Raise out of friendship hostil deeds in Peace. The conquerd also, and enslav'd by Warr Shall with thir freedom lost all vertu loose And feare of God, from whom thir pietie feign'd In sharp contest of Battel found no aide Against invaders; therefore coold in zeale Thenceforth shall practice how to live secure, Worldlie or dissolute, on what thir Lords Shall leave them to enjoy; for th' Earth shall bear More then anough, that temperance may be tri'd: So all shall turn degenerate, all deprav'd, Justice and Temperance, Truth and Faith forgot; One Man except, the onely Son of light In a dark Age, against example good, Against allurement, custom, and a World Offended; fearless of reproach and scorn, Or violence, hee of thir wicked wayes Shall them admonish, and before them set The paths of righteousness, how much more safe, And full of peace, denouncing wrauth to come On thir impenitence; and shall returne Of them derided, but of God observd The one just Man alive; by his command Shall build a wondrous Ark, as thou beheldst, To save himself and houshold from amidst A World devote to universal rack. No sooner hee with them of Man and Beast Select for life shall in the Ark be lodg'd, And shelterd round, but all the Cataracts Of Heav'n set open on the Earth shall powre Raine day and night, all fountaines of the Deep Broke up, shall heave the Ocean to usurp Beyond all bounds, till inundation rise Above the highest Hills: then shall this Mount Of Paradise by might of Waves be moovd Out of his place, pushd by the horned floud, With all his verdure spoil'd, and Trees adrift Down the great River to the op'ning Gulf, And there take root an Iland salt and bare, The haunt of Seales and Orcs, and Sea-mews clang. To teach thee that God attributes to place No sanctitie, if none be thither brought By Men who there frequent, or therein dwell. And now what further shall ensue, behold. He lookd, and saw the Ark hull on the floud, Which now abated, for the Clouds were fled, Drivn by a keen North-winde, that blowing drie Wrinkl'd the face of Deluge, as decai'd; And the cleer Sun on his wide watrie Glass Gaz'd hot, and of the fresh Wave largely drew, As after thirst, which made thir flowing shrink From standing lake to tripping ebbe, that stole With soft foot towards the deep, who now had stopt His Sluces, as the Heav'n his windows shut. The Ark no more now flotes, but seems on ground Fast on the top of som high mountain fixt. And now the tops of Hills as Rocks appeer; With clamor thence the rapid Currents drive Towards the retreating Sea thir furious tyde. Forthwith from out the Arke a Raven flies, And after him, the surer messenger, A Dove sent forth once and agen to spie Green Tree or ground whereon his foot may light; The second time returning, in his Bill An Olive leafe he brings, pacific signe: Anon drie ground appeers, and from his Arke The ancient Sire descends with all his Train; Then with uplifted hands, and eyes devout, Grateful to Heav'n, over his head beholds A dewie Cloud, and in the Cloud a Bow Conspicuous with three lifted colours gay, Betok'ning peace from God, and Cov'nant new. Whereat the heart of ADAM erst so sad Greatly rejoyc'd, and thus his joy broke forth. O thou that future things canst represent As present, Heav'nly instructer, I revive At this last sight, assur'd that Man shall live With all the Creatures, and thir seed preserve. Farr less I now lament for one whole World Of wicked Sons destroyd, then I rejoyce For one Man found so perfet and so just, That God voutsafes to raise another World From him, and all his anger to forget. But say, what mean those colourd streaks in Heavn, Distended as the Brow of God appeas'd, Or serve they as a flourie verge to binde The fluid skirts of that same watrie Cloud, Least it again dissolve and showr the Earth? To whom th' Archangel. Dextrously thou aim'st; So willingly doth God remit his Ire, Though late repenting him of Man deprav'd, Griev'd at his heart, when looking down he saw The whole Earth fill'd with violence, and all flesh Corrupting each thir way; yet those remoov'd, Such grace shall one just Man find in his sight, That he relents, not to blot out mankind, And makes a Covenant never to destroy The Earth again by flood, nor let the Sea Surpass his bounds, nor Rain to drown the World With Man therein or Beast; but when he brings Over the Earth a Cloud, will therein set His triple-colour'd Bow, whereon to look And call to mind his Cov'nant: Day and Night, Seed time and Harvest, Heat and hoary Frost Shall hold thir course, till fire purge all things new, Both Heav'n and Earth, wherein the just shall dwell. Thus thou hast seen one World begin and end; And Man as from a second stock proceed. Much thou hast yet to see, but I perceave Thy mortal sight to faile; objects divine Must needs impaire and wearie human sense: Henceforth what is to com I will relate, Thou therefore give due audience, and attend. This second sours of Men, while yet but few, And while the dread of judgement past remains Fresh in thir mindes, fearing the Deitie, With some regard to what is just and right Shall lead thir lives, and multiplie apace, Labouring the soile, and reaping plenteous crop, Corn wine and oyle; and from the herd or flock, Oft sacrificing Bullock, Lamb, or Kid, With large Wine-offerings pour'd, and sacred Feast Shal spend thir dayes in joy unblam'd, and dwell Long time in peace by Families and Tribes Under paternal rule; till one shall rise Of proud ambitious heart, who not content With fair equalitie, fraternal state, Will arrogate Dominion undeserv'd Over his brethren, and quite dispossess Concord and law of Nature from the Earth; Hunting (and Men not Beasts shall be his game) With Warr and hostile snare such as refuse Subjection to his Empire tyrannous: A mightie Hunter thence he shall be styl'd Before the Lord, as in despite of Heav'n, Or from Heav'n claming second Sovrantie; And from Rebellion shall derive his name, Though of Rebellion others he accuse. Hee with a crew, whom like Ambition joyns With him or under him to tyrannize, Marching from EDEN towards the West, shall finde The Plain, wherein a black bituminous gurge Boiles out from under ground, the mouth of Hell; Of Brick, and of that stuff they cast to build A Citie & Towre, whose top may reach to Heav'n; And get themselves a name, least far disperst In foraign Lands thir memorie be lost, Regardless whether good or evil fame. But God who oft descends to visit men Unseen, and through thir habitations walks To mark thir doings, them beholding soon, Comes down to see thir Citie, ere the Tower Obstruct Heav'n Towrs, and in derision sets Upon thir Tongues a various Spirit to rase Quite out thir Native Language, and instead To sow a jangling noise of words unknown: Forthwith a hideous gabble rises loud Among the Builders; each to other calls Not understood, till hoarse, and all in rage, As mockt they storm; great laughter was in Heav'n And looking down, to see the hubbub strange And hear the din; thus was the building left Ridiculous, and the work Confusion nam'd. Whereto thus ADAM fatherly displeas'd. O execrable Son so to aspire Above his Brethren, to himself affirming Authoritie usurpt, from God not giv'n: He gave us onely over Beast, Fish, Fowl Dominion absolute; that right we hold By his donation; but Man over men He made not Lord; such title to himself Reserving, human left from human free. But this Usurper his encroachment proud Stayes not on Man; to God his Tower intends Siege and defiance: Wretched man! what food Will he convey up thither to sustain Himself and his rash Armie, where thin Aire Above the Clouds will pine his entrails gross, And famish him of Breath, if not of Bread? To whom thus MICHAEL. Justly thou abhorr'st That Son, who on the quiet state of men Such trouble brought, affecting to subdue Rational Libertie; yet know withall, Since thy original lapse, true Libertie Is lost, which alwayes with right Reason dwells Twinn'd, and from her hath no dividual being: Reason in man obscur'd, or not obeyd, Immediately inordinate desires And upstart Passions catch the Government From Reason, and to servitude reduce Man till then free. Therefore since hee permits Within himself unworthie Powers to reign Over free Reason, God in Judgement just Subjects him from without to violent Lords; Who oft as undeservedly enthrall His outward freedom: Tyrannie must be, Though to the Tyrant thereby no excuse. Yet somtimes Nations will decline so low From vertue, which is reason, that no wrong, But Justice, and some fatal curse annext Deprives them of thir outward libertie, Thir inward lost: Witness th' irreverent Son Of him who built the Ark, who for the shame Don to his Father, heard this heavie curse, SERVANT OF SERVANTS, on his vitious Race. Thus will this latter, as the former World, Still tend from bad to worse, till God at last Wearied with their iniquities, withdraw His presence from among them, and avert His holy Eyes; resolving from thenceforth To leave them to thir own polluted wayes; And one peculiar Nation to select From all the rest, of whom to be invok'd, A Nation from one faithful man to spring: Him on this side EUPHRATES yet residing, Bred up in Idol-worship; O that men (Canst thou believe?) should be so stupid grown, While yet the Patriark liv'd, who scap'd the Flood, As to forsake the living God, and fall To-worship thir own work in Wood and Stone For Gods! yet him God the most High voutsafes To call by Vision from his Fathers house, His kindred and false Gods, into a Land Which he will shew him, and from him will raise A mightie Nation, and upon him showre His benediction so, that in his Seed All Nations shall be blest; hee straight obeys, Not knowing to what Land, yet firm believes: I see him, but thou canst not, with what Faith He leaves his Gods, his Friends, and native Soile UR of CHALDAEA, passing now the Ford To HARAN, after him a cumbrous Train Of Herds and Flocks, and numerous servitude; Not wandring poor, but trusting all his wealth With God, who call'd him, in a land unknown. CANAAN he now attains, I see his Tents Pitcht about SECHEM, and the neighbouring Plaine Of MOREB; there by promise he receaves Gift to his Progenie of all that Land; From HAMATH Northward to the Desert South (Things by thir names I call, though yet unnam'd) From HERMON East to the great Western Sea, Mount HERMON, yonder Sea, each place behold In prospect, as I point them; on the shoare Mount CARMEL; here the double-founted stream JORDAN, true limit Eastward; but his Sons Shall dwell to SENIR, that long ridge of Hills. This ponder, that all Nations of the Earth Shall in his Seed be blessed; by that Seed Is meant thy great deliverer, who shall bruise The Serpents head; whereof to thee anon Plainlier shall be reveald. This Patriarch blest, Whom FAITHFUL ABRAHAM due time shall call, A Son, and of his Son a Grand-childe leaves, Like him in faith, in wisdom, and renown; The Grandchilde with twelve Sons increast, departs From CANAAN, to a Land hereafter call'd EGYPT, divided by the River NILE; See where it flows, disgorging at seaven mouthes Into the Sea: to sojourn in that Land He comes invited by a yonger Son In time of dearth, a Son whose worthy deeds Raise him to be the second in that Realme Of PHARAO: there he dies, and leaves his Race Growing into a Nation, and now grown Suspected to a sequent King, who seeks To stop thir overgrowth, as inmate guests Too numerous; whence of guests he makes them slaves Inhospitably, and kills thir infant Males: Till by two brethren (those two brethren call MOSES and AARON) sent from God to claime His people from enthralment, they return With glory and spoile back to thir promis'd Land. But first the lawless Tyrant, who denies To know thir God, or message to regard, Must be compelld by Signes and Judgements dire; To blood unshed the Rivers must be turnd, Frogs, Lice and Flies must all his Palace fill With loath'd intrusion, and fill all the land; His Cattel must of Rot and Murren die, Botches and blaines must all his flesh imboss, And all his people; Thunder mixt with Haile, Haile mixt with fire must rend th' EGYPTIAN Skie And wheel on th' Earth, devouring where it rouls; What it devours not, Herb, or Fruit, or Graine, A darksom Cloud of Locusts swarming down Must eat, and on the ground leave nothing green: Darkness must overshadow all his bounds, Palpable darkness, and blot out three dayes; Last with one midnight stroke all the first-born Of EGYPT must lie dead. Thus with ten wounds This River-dragon tam'd at length submits To let his sojourners depart, and oft Humbles his stubborn heart, but still as Ice More hard'nd after thaw, till in his rage Pursuing whom he late dismissd, the Sea Swallows him with his Host, but them lets pass As on drie land between two christal walls, Aw'd by the rod of MOSES so to stand Divided, till his rescu'd gain thir shoar: Such wondrous power God to his Saint will lend, Though present in his Angel, who shall goe Before them in a Cloud, and Pillar of Fire, To guide them in thir journey, and remove Behinde them, while th' obdurat King pursues: All night he will pursue, but his approach Darkness defends between till morning Watch; Then through the Firey Pillar and the Cloud God looking forth will trouble all his Host And craze thir Chariot wheels: when by command MOSES once more his potent Rod extends Over the Sea; the Sea his Rod obeys; On thir imbattelld ranks the Waves return, And overwhelm thir Warr: the Race elect Safe towards CANAAN from the shoar advance Through the wilde Desert, not the readiest way, Least entring on the CANAANITE allarmd Warr terrifie them inexpert, and feare Return them back to EGYPT, choosing rather Inglorious life with servitude; for life To noble and ignoble is more sweet Untraind in Armes, where rashness leads not on. This also shall they gain by thir delay In the wide Wilderness, there they shall found Thir government, and thir great Senate choose Through the twelve Tribes, to rule by Laws ordaind: God from the Mount of SINAI, whose gray top Shall tremble, he descending, will himself In Thunder Lightning and loud Trumpets sound Ordaine them Lawes; part such as appertaine To civil Justice, part religious Rites Of sacrifice, informing them, by types And shadowes, of that destind Seed to bruise The Serpent, by what meanes he shall achieve Mankinds deliverance. But the voice of God To mortal eare is dreadful; they beseech That MOSES might report to them his will, And terror cease; he grants them thir desire, Instructed that to God is no access Without Mediator, whose high Office now MOSES in figure beares, to introduce One greater, of whose day he shall foretell, And all the Prophets in thir Age the times Of great MESSIAH shall sing. Thus Laws and Rites Establisht, such delight hath God in Men Obedient to his will, that he voutsafes Among them to set up his Tabernacle, The holy One with mortal Men to dwell: By his prescript a Sanctuary is fram'd Of Cedar, overlaid with Gold, therein An Ark, and in the Ark his Testimony, The Records of his Cov'nant, over these A Mercie-seat of Gold between the wings Of two bright Cherubim, before him burn Seaven Lamps as in a Zodiac representing The Heav'nly fires; over the Tent a Cloud Shall rest by Day, a fierie gleame by Night, Save when they journie, and at length they come, Conducted by his Angel to the Land Promisd to ABRAHAM and his Seed: the rest Were long to tell, how many Battels fought, How many Kings destroyd, and Kingdoms won, Or how the Sun shall in mid Heav'n stand still A day entire, and Nights due course adjourne, Mans voice commanding, Sun in GIBEON stand, And thou Moon in the vale of AIALON, Till ISRAEL overcome; so call the third From ABRAHAM, Son of ISAAC, and from him His whole descent, who thus shall CANAAN win. Here ADAM interpos'd. O sent from Heav'n, Enlightner of my darkness, gracious things Thou hast reveald, those chiefly which concerne Just ABRAHAM and his Seed: now first I finde Mine eyes true op'ning, and my heart much eas'd, Erwhile perplext with thoughts what would becom Of mee and all Mankind; but now I see His day, in whom all Nations shall be blest, Favour unmerited by me, who sought Forbidd'n knowledge by forbidd'n means. This yet I apprehend not, why to those Among whom God will deigne to dwell on Earth So many and so various Laws are giv'n; So many Laws argue so many sins Among them; how can God with such reside? To whom thus MICHAEL. Doubt not but that sin Will reign among them, as of thee begot; And therefore was Law given them to evince Thir natural pravitie, by stirring up Sin against Law to fight; that when they see Law can discover sin, but not remove, Save by those shadowie expiations weak, The bloud of Bulls and Goats, they may conclude Some bloud more precious must be paid for Man, Just for unjust, that in such righteousness To them by Faith imputed, they may finde Justification towards God, and peace Of Conscience, which the Law by Ceremonies Cannot appease, nor Man the moral part Perform, and not performing cannot live. So Law appears imperfet, and but giv'n With purpose to resign them in full time Up to a better Cov'nant, disciplin'd From shadowie Types to Truth, from Flesh to Spirit, From imposition of strict Laws, to free Acceptance of large Grace, from servil fear To filial, works of Law to works of Faith. And therefore shall not MOSES, though of God Highly belov'd, being but the Minister Of Law, his people into CANAAN lead; But JOSHUA whom the Gentiles JESUS call, His Name and Office bearing, who shall quell The adversarie Serpent, and bring back Through the worlds wilderness long wanderd man Safe to eternal Paradise of rest. Meanwhile they in thir earthly CANAAN plac't Long time shall dwell and prosper, but when sins National interrupt thir public peace, Provoking God to raise them enemies: From whom as oft he saves them penitent By Judges first, then under Kings; of whom The second, both for pietie renownd And puissant deeds, a promise shall receive Irrevocable, that his Regal Throne For ever shall endure; the like shall sing All Prophecie, That of the Royal Stock Of DAVID (so I name this King) shall rise A Son, the Womans Seed to thee foretold, Foretold to ABRAHAM, as in whom shall trust All Nations, and to Kings foretold, of Kings The last, for of his Reign shall be no end. But first a long succession must ensue, And his next Son for Wealth and Wisdom fam'd, The clouded Ark of God till then in Tents Wandring, shall in a glorious Temple enshrine. Such follow him, as shall be registerd Part good, part bad, of bad the longer scrowle, Whose foul Idolatries, and other faults Heapt to the popular summe, will so incense God, as to leave them, and expose thir Land, Thir Citie, his Temple, and his holy Ark With all his sacred things, a scorn and prey To that proud Citie, whose high Walls thou saw'st Left in confusion, BABYLON thence call'd. There in captivitie he lets them dwell The space of seventie years, then brings them back, Remembring mercie, and his Cov'nant sworn To DAVID, stablisht as the dayes of Heav'n. Returnd from BABYLON by leave of Kings Thir Lords, whom God dispos'd, the house of God They first re-edifie, and for a while In mean estate live moderate, till grown In wealth and multitude, factious they grow; But first among the Priests dissension springs, Men who attend the Altar, and should most Endeavour Peace: thir strife pollution brings Upon the Temple it self: at last they seise The Scepter, and regard not DAVIDS Sons, Then loose it to a stranger, that the true Anointed King MESSIAH might be born Barr'd of his right; yet at his Birth a Starr Unseen before in Heav'n proclaims him com, And guides the Eastern Sages, who enquire His place, to offer Incense, Myrrh, and Gold; His place of birth a solemn Angel tells To simple Shepherds, keeping watch by night; They gladly thither haste, and by a Quire Of squadrond Angels hear his Carol sung. A Virgin is his Mother, but his Sire The Power of the most High; he shall ascend The Throne hereditarie, and bound his Reign With earths wide bounds, his glory with the Heav'ns. He ceas'd, discerning ADAM with such joy Surcharg'd, as had like grief bin dew'd in tears, Without the vent of words, which these he breathd. O Prophet of glad tidings, finisher Of utmost hope! now clear I understand What oft my steddiest thoughts have searcht in vain, Why our great expectation should be call'd The seed of Woman: Virgin Mother, Haile, High in the love of Heav'n, yet from my Loynes Thou shalt proceed, and from thy Womb the Son Of God most High; So God with man unites. Needs must the Serpent now his capital bruise Expect with mortal paine: say where and when Thir fight, what stroke shall bruise the Victors heel. To whom thus MICHAEL. Dream not of thir fight, As of a Duel, or the local wounds Of head or heel: not therefore joynes the Son Manhood to God-head, with more strength to foil Thy enemie; nor so is overcome SATAN, whose fall from Heav'n, a deadlier bruise, Disabl'd not to give thee thy deaths wound: Which hee, who comes thy Saviour, shall recure, Not by destroying SATAN, but his works In thee and in thy Seed: nor can this be, But by fulfilling that which thou didst want, Obedience to the Law of God, impos'd On penaltie of death, and suffering death, The penaltie to thy transgression due, And due to theirs which out of thine will grow: So onely can high Justice rest appaid. The Law of God exact he shall fulfill Both by obedience and by love, though love Alone fulfill the Law; thy punishment He shall endure by coming in the Flesh To a reproachful life and cursed death, Proclaiming Life to all who shall believe In his redemption, and that his obedience Imputed becomes theirs by Faith, his merits To save them, not thir own, though legal works. For this he shall live hated, be blasphem'd, Seis'd on by force, judg'd, and to death condemnd A shameful and accurst, naild to the Cross By his own Nation, slaine for bringing Life; But to the Cross he nailes thy Enemies, The Law that is against thee, and the sins Of all mankinde, with him there crucifi'd, Never to hurt them more who rightly trust In this his satisfaction; so he dies, But soon revives, Death over him no power Shall long usurp; ere the third dawning light Returne, the Starres of Morn shall see him rise Out of his grave, fresh as the dawning light, Thy ransom paid, which Man from death redeems, His death for Man, as many as offerd Life Neglect not, and the benefit imbrace By Faith not void of works: this God-like act Annuls thy doom, the death thou shouldst have dy'd, In sin for ever lost from life; this act Shall bruise the head of SATAN, crush his strength Defeating Sin and Death, his two maine armes, And fix farr deeper in his head thir stings Then temporal death shall bruise the Victors heel, Or theirs whom he redeems, a death like sleep, A gentle wafting to immortal Life. Nor after resurrection shall he stay Longer on Earth then certaine times to appeer To his Disciples, Men who in his Life Still follow'd him; to them shall leave in charge To teach all nations what of him they learn'd And his Salvation, them who shall beleeve Baptizing in the profluent streame, the signe Of washing them from guilt of sin to Life Pure, and in mind prepar'd, if so befall, For death, like that which the redeemer dy'd. All Nations they shall teach; for from that day Not onely to the Sons of ABRAHAMS Loines Salvation shall be Preacht, but to the Sons Of ABRAHAMS Faith wherever through the world; So in his seed all Nations shall be blest. Then to the Heav'n of Heav'ns he shall ascend With victory, triumphing through the aire Over his foes and thine; there shall surprise The Serpent, Prince of aire, and drag in Chaines Through all his realme, & there confounded leave; Then enter into glory, and resume His Seat at Gods right hand, exalted high Above all names in Heav'n; and thence shall come, When this worlds dissolution shall be ripe, With glory and power to judge both quick & dead, To judge th' unfaithful dead, but to reward His faithful, and receave them into bliss, Whether in Heav'n or Earth, for then the Earth Shall all be Paradise, far happier place Then this of EDEN, and far happier daies. So spake th' Archangel MICHAEL, then paus'd, As at the Worlds great period; and our Sire Replete with joy and wonder thus repli'd. O goodness infinite, goodness immense! That all this good of evil shall produce, And evil turn to good; more wonderful Then that which by creation first brought forth Light out of darkness! full of doubt I stand, Whether I should repent me now of sin By mee done and occasiond, or rejoyce Much more, that much more good thereof shall spring, To God more glory, more good will to Men From God, and over wrauth grace shall abound. But say, if our deliverer up to Heav'n Must reascend, what will betide the few His faithful, left among th' unfaithful herd, The enemies of truth; who then shall guide His people, who defend? will they not deale Wors with his followers then with him they dealt? Be sure they will, said th' Angel; but from Heav'n Hee to his own a Comforter will send, The promise of the Father, who shall dwell His Spirit within them, and the Law of Faith Working through love, upon thir hearts shall write, To guide them in all truth, and also arme With spiritual Armour, able to resist SATANS assaults, and quench his fierie darts What Man can do against them, not affraid, Though to the death, against such cruelties With inward consolations recompenc't, And oft supported so as shall amaze Thir proudest persecuters: for the Spirit Powrd first on his Apostles, whom he sends To evangelize the Nations, then on all Baptiz'd, shall them with wondrous gifts endue To speak all Tongues, and do all Miracles, As did thir Lord before them. Thus they win Great numbers of each Nation to receave With joy the tidings brought from Heav'n: at length Thir Ministry perform'd, and race well run, Thir doctrine and thir story written left, They die; but in thir room, as they forewarne, Wolves shall succeed for teachers, grievous Wolves, Who all the sacred mysteries of Heav'n To thir own vile advantages shall turne Of lucre and ambition, and the truth With superstitions and traditions taint, Left onely in those written Records pure, Though not but by the Spirit understood. Then shall they seek to avail themselves of names, Places and titles, and with these to joine Secular power, though feigning still to act By spiritual, to themselves appropriating The Spirit of God, promisd alike and giv'n To all Beleevers; and from that pretense, Spiritual Lawes by carnal power shall force On every conscience; Laws which none shall finde Left them inrould, or what the Spirit within Shall on the heart engrave. What will they then But force the Spirit of Grace it self, and binde His consort Libertie; what, but unbuild His living Temples, built by Faith to stand, Thir own Faith not anothers: for on Earth Who against Faith and Conscience can be heard Infallible? yet many will presume: Whence heavie persecution shall arise On all who in the worship persevere Of Spirit and Truth; the rest, farr greater part, Will deem in outward Rites and specious formes Religion satisfi'd; Truth shall retire Bestuck with slandrous darts, and works of Faith Rarely be found: so shall the World goe on, To good malignant, to bad men benigne, Under her own waight groaning, till the day Appeer of respiration to the just, And vengeance to the wicked, at return Of him so lately promis'd to thy aid, The Womans seed, obscurely then foretold, Now amplier known thy Saviour and thy Lord, Last in the Clouds from Heav'n to be reveald In glory of the Father, to dissolve SATAN with his perverted World, then raise From the conflagrant mass, purg'd and refin'd, New Heav'ns, new Earth, Ages of endless date Founded in righteousness and peace and love, To bring forth fruits Joy and eternal Bliss. He ended; and thus ADAM last reply'd. How soon hath thy prediction, Seer blest, Measur'd this transient World, the Race of time, Till time stand fixt: beyond is all abyss, Eternitie, whose end no eye can reach. Greatly instructed I shall hence depart, Greatly in peace of thought, and have my fill Of knowledge, what this vessel can containe; Beyond which was my folly to aspire. Henceforth I learne, that to obey is best, And love with feare the onely God, to walk As in his presence, ever to observe His providence, and on him sole depend, Merciful over all his works, with good Still overcoming evil, and by small Accomplishing great things, by things deemd weak Subverting worldly strong, and worldly wise By simply meek; that suffering for Truths sake Is fortitude to highest victorie, And to the faithful Death the Gate of Life; Taught this by his example whom I now Acknowledge my Redeemer ever blest. To whom thus also th' Angel last repli'd: This having learnt, thou hast attaind the summe Of wisdom; hope no higher, though all the Starrs Thou knewst by name, and all th' ethereal Powers, All secrets of the deep, all Natures works, Or works of God in Heav'n, Air, Earth, or Sea, And all the riches of this World enjoydst, And all the rule, one Empire; onely add Deeds to thy knowledge answerable, add Faith, Add Vertue, Patience, Temperance, add Love, By name to come call'd Charitie, the soul Of all the rest: then wilt thou not be loath To leave this Paradise, but shalt possess A Paradise within thee, happier farr. Let us descend now therefore from this top Of Speculation; for the hour precise Exacts our parting hence; and see the Guards, By mee encampt on yonder Hill, expect Thir motion, at whose Front a flaming Sword, In signal of remove, waves fiercely round; We may no longer stay: go, waken Eve; Her also I with gentle Dreams have calm'd Portending good, and all her spirits compos'd To meek submission: thou at season fit Let her with thee partake what thou hast heard, Chiefly what may concern her Faith to know, The great deliverance by her Seed to come (For by the Womans Seed) on all Mankind. That ye may live, which will be many dayes, Both in one Faith unanimous though sad, With cause for evils past, yet much more cheer'd With meditation on the happie end. He ended, and they both descend the Hill; Descended, ADAM to the Bowre where EVE Lay sleeping ran before, but found her wak't; And thus with words not sad she him receav'd. Whence thou returnst, & whither wentst, I know; For God is also in sleep, and Dreams advise, Which he hath sent propitious, some great good Presaging, since with sorrow and hearts distress VVearied I fell asleep: but now lead on; In mee is no delay; with thee to goe, Is to stay here; without thee here to stay, Is to go hence unwilling; thou to mee Art all things under Heav'n, all places thou, VVho for my wilful crime art banisht hence. This further consolation yet secure I carry hence; though all by mee is lost, Such favour I unworthie am voutsaft, By mee the Promis'd Seed shall all restore. So spake our Mother EVE, and ADAM heard VVell pleas'd, but answer'd not; for now too nigh Th' Archangel stood, and from the other Hill To thir fixt Station, all in bright array The Cherubim descended; on the ground Gliding meteorous, as Ev'ning Mist Ris'n from a River o're the marish glides, And gathers ground fast at the Labourers heel Homeward returning. High in Front advanc't, The brandisht Sword of God before them blaz'd Fierce as a Comet; which with torrid heat, And vapour as the LIBYAN Air adust, Began to parch that temperate Clime; whereat In either hand the hastning Angel caught Our lingring Parents, and to th' Eastern Gate Let them direct, and down the Cliff as fast To the subjected Plaine; then disappeer'd. They looking back, all th' Eastern side beheld Of Paradise, so late thir happie seat, Wav'd over by that flaming Brand, the Gate With dreadful Faces throng'd and fierie Armes: Som natural tears they drop'd, but wip'd them soon; The World was all before them, where to choose Thir place of rest, and Providence thir guide: They hand in hand with wandring steps and slow, Through EDEN took thir solitarie way. THE END.  xappy-0.5/testsuite/0000755000175000017500000000000011005556727014372 5ustar richardrichardxappy-0.5/testsuite/unittests/0000755000175000017500000000000011005556727016434 5ustar richardrichardxappy-0.5/testsuite/unittests/facet_hierarchy_1.py0000644000175000017500000001115510770031412022334 0ustar richardrichardfrom unittest import TestCase, main import tempfile, os, sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..')) from xappy.indexerconnection import * from xappy.fieldactions import * from xappy.searchconnection import * # Facets used in documents and their parent facets (or None for top-level facets) facets = { 'category': None, 'colour': None, 'type': 'category', 'make': 'category', 'species': 'category', 'strings': 'type', } # Documents docvalues = [ { 'category': 'instrument', 'colour': 'blue', 'type': 'drums', 'make': 'Gretsch', }, { 'category': 'instrument', 'colour': 'red', 'type': 'drums', 'make': 'Stagg', 'offer': '2 for 1', }, { 'category': 'instrument', 'colour': 'black', 'type': 'accessories', 'make': 'Yamaha', }, { 'category': 'instrument', 'colour': 'brown', 'type': 'bass guitar', 'make': 'Musicman', 'strings': '4', }, { 'category': 'instrument', 'colour': 'green', 'type': 'bass guitar', 'make': 'Yamaha', 'strings': '5', }, { 'category': 'animal', 'colour': 'black', 'species': 'Persian', }, { 'category': 'animal', 'colour': 'grey', 'species': 'husky', }, ] class TestFacetHierarchy(TestCase): def setUp(self): tempdir = tempfile.mkdtemp() self.indexpath = os.path.join(tempdir, 'foo') iconn = IndexerConnection(self.indexpath) for name in facets: iconn.add_field_action(name, FieldActions.INDEX_EXACT) iconn.add_field_action(name, FieldActions.STORE_CONTENT) iconn.add_field_action(name, FieldActions.FACET) for name, parent in facets.iteritems(): if parent: iconn.add_subfacet(name, parent) for values in docvalues: doc = UnprocessedDocument() for name, value in values.iteritems(): doc.fields.append(Field(name, value)) iconn.add(doc) iconn.flush() iconn.close() self.sconn = SearchConnection(self.indexpath) self.faceted_query = self.sconn.query_facet('category', 'instrument') def _get_facets(self, query, usesubfacets=None, maxfacets=100, required_facets=None): results = self.sconn.search(query, 0, 10, getfacets=True, usesubfacets=usesubfacets) tuples = results.get_suggested_facets(maxfacets=maxfacets, required_facets=required_facets) return set([tuple[0] for tuple in tuples]) def test_non_hierarchy(self): # Test that all facets with > 1 value are suggested when the m-set is all documents assert self._get_facets(self.sconn.query_all()) == set(['colour', 'category', 'species', 'type', 'make', 'strings']) # Test that all facets on instruments are returned for the faceted query assert self._get_facets(self.faceted_query) == set(['colour', 'type', 'make', 'strings']) def test_hierarchy(self): # Test that only top-level facets are suggested for a non-faceted query for all documents assert self._get_facets(self.sconn.query_all(), usesubfacets=True) == set(['colour', 'category']) # Test that only top-level facets and subfacets of category are suggested for the faceted query, # but not 'category' for which there is only 1 value assert self._get_facets(self.faceted_query, usesubfacets=True) == set(['make', 'type', 'colour']) # Test that subfacets 'make' and 'type' are suggested first over the top-level facet 'colour' assert self._get_facets(self.faceted_query, usesubfacets=True, maxfacets=2) == set(['make', 'type']) # Test that if we explicitely ask for 'category' then we get it regardless assert self._get_facets(self.faceted_query, usesubfacets=True, required_facets='category') == set(['make', 'type', 'colour', 'category']) def tearDown(self): self.sconn.close() if __name__ == '__main__': main() xappy-0.5/testsuite/unittests/facet_query_type_1.py0000644000175000017500000001052510772155125022576 0ustar richardrichardfrom unittest import TestCase, main import tempfile, os, sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..')) from xappy.indexerconnection import * from xappy.fieldactions import * from xappy.searchconnection import * # Facets used in documents facets = [ 'category', 'colour', 'type', 'make', 'species', 'strings', ] # Documents docvalues = [ { 'category': 'instrument', 'colour': 'blue', 'type': 'drums', 'make': 'Gretsch', }, { 'category': 'instrument', 'colour': 'red', 'type': 'drums', 'make': 'Stagg', }, { 'category': 'instrument', 'colour': 'black', 'type': 'accessories', 'make': 'Yamaha', }, { 'category': 'instrument', 'colour': 'brown', 'type': 'bass guitar', 'make': 'Musicman', 'strings': '4', }, { 'category': 'instrument', 'colour': 'green', 'type': 'bass guitar', 'make': 'Yamaha', 'strings': '5', }, ] class TestFacetHierarchy(TestCase): def setUp(self): tempdir = tempfile.mkdtemp() indexpath = os.path.join(tempdir, 'foo') self.iconn = IndexerConnection(indexpath) for name in facets: self.iconn.add_field_action(name, FieldActions.INDEX_EXACT) self.iconn.add_field_action(name, FieldActions.STORE_CONTENT) self.iconn.add_field_action(name, FieldActions.FACET) for values in docvalues: doc = UnprocessedDocument() for name, value in values.iteritems(): doc.fields.append(Field(name, value)) self.iconn.add(doc) self.iconn.set_facet_for_query_type('type1', 'colour', self.iconn.FacetQueryType_Preferred) self.iconn.set_facet_for_query_type('type1', 'colour', self.iconn.FacetQueryType_Never) self.iconn.set_facet_for_query_type('type2', 'colour', self.iconn.FacetQueryType_Preferred) self.iconn.set_facet_for_query_type('type2', 'make', self.iconn.FacetQueryType_Preferred) self.iconn.set_facet_for_query_type('type3', 'colour', self.iconn.FacetQueryType_Preferred) self.iconn.set_facet_for_query_type('type3', 'colour', None) self.iconn.flush() self.sconn = SearchConnection(indexpath) def _get_facets(self, query, maxfacets=100, query_type=None): results = self.sconn.search(query, 0, 10, getfacets=True, query_type=query_type) tuples = results.get_suggested_facets(maxfacets=maxfacets) return set([tuple[0] for tuple in tuples]) def test_facet_query_types(self): # Test facets have the right preference for query types assert self.iconn.get_facets_for_query_type('type1', self.iconn.FacetQueryType_Never) == set(['colour']) assert self.iconn.get_facets_for_query_type('type1', self.iconn.FacetQueryType_Preferred) == set() assert self.iconn.get_facets_for_query_type('type2', self.iconn.FacetQueryType_Preferred) == set(['colour', 'make']) assert self.iconn.get_facets_for_query_type('type3', self.iconn.FacetQueryType_Preferred) == None assert self.iconn.get_facets_for_query_type('not_a_type', self.iconn.FacetQueryType_Preferred) == None def test_facet_search(self): query = self.sconn.query_facet('category', 'instrument') # Test suggested facets are what we expect assert self._get_facets(query) == set(['colour', 'type', 'make', 'strings']); # Test 'colour' not suggested for query_type 'type1' assert self._get_facets(query, query_type='type1') == set(['type', 'make', 'strings']); # Test 'colour' and 'make' preferred for query_type 'type2' assert self._get_facets(query, query_type='type2', maxfacets=2) == set(['colour', 'make']); def tearDown(self): self.iconn.close() self.sconn.close() if __name__ == '__main__': main() xappy-0.5/testsuite/unittests/freetext_1.py0000644000175000017500000001212211001754033021034 0ustar richardrichardfrom unittest import TestCase, main import os, shutil, sys, tempfile sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..')) from xappy import * class TestFreeText(TestCase): def setUp(self): self.tempdir = tempfile.mkdtemp() self.indexpath = os.path.join(self.tempdir, 'foo') iconn = IndexerConnection(self.indexpath) iconn.add_field_action('a', FieldActions.INDEX_FREETEXT) iconn.add_field_action('b', FieldActions.INDEX_FREETEXT, search_by_default=False) iconn.add_field_action('c', FieldActions.INDEX_FREETEXT, search_by_default=True) iconn.add_field_action('d', FieldActions.INDEX_FREETEXT, allow_field_specific=False) iconn.add_field_action('e', FieldActions.INDEX_FREETEXT, allow_field_specific=True) iconn.add_field_action('f', FieldActions.INDEX_FREETEXT, search_by_default=False, allow_field_specific=False) iconn.add_field_action('a', FieldActions.STORE_CONTENT) iconn.add_field_action('b', FieldActions.STORE_CONTENT) iconn.add_field_action('c', FieldActions.STORE_CONTENT) for i in xrange(32): doc = UnprocessedDocument() if i % 2: doc.fields.append(Field('a', 'termA')) if (i / 2) % 2: doc.fields.append(Field('b', 'termB')) if (i / 4) % 2: doc.fields.append(Field('c', 'termC')) if (i / 8) % 2: doc.fields.append(Field('d', 'termD')) if (i / 16) % 2: doc.fields.append(Field('e', 'termE')) if (i / 3) % 3 == 0: doc.fields.append(Field('f', 'termF')) iconn.add(doc) iconn.flush() iconn.close() self.sconn = SearchConnection(self.indexpath) def test_search_by_default1(self): # Search by default (due to default handling) q = self.sconn.query_parse('termA') res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31])) # Not searched by default q = self.sconn.query_parse('termB') res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([])) # Explicitly searched by default q = self.sconn.query_parse('termC') res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31])) # Not searched by default q = self.sconn.query_parse('termF') res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([])) def test_search_by_default2(self): # Search by default (due to default handling) q = self.sconn.query_parse('termA', default_allow=('a', )) res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31])) # Not searched by default, but can be explicitly specified q = self.sconn.query_parse('termB', default_allow=('b', )) res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31])) # Explicitly searched by default q = self.sconn.query_parse('termC', default_allow=('c', )) res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31])) # Not searched by default, by can't be explicitly specified either # because it's not indexed as allow_field_specific q = self.sconn.query_parse('termF') res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([])) def test_allow_field_specific1(self): # Search by default (due to default handling) q = self.sconn.query_parse('a:termA', allow=('a', )) res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31])) # Not indexed for field specific searching q = self.sconn.query_parse('d:termD', allow=('d', )) res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([])) # Explicitly indexed for field specific searching q = self.sconn.query_parse('e:termE', allow=('e', )) res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])) # Not indexed for field specific searching q = self.sconn.query_parse('termF') res = self.sconn.search(q, 0, 100) self.assertEqual(set([int(item.id, 16) for item in res]), set([])) def tearDown(self): self.sconn.close() #shutil.rmtree(self.tempdir) if __name__ == '__main__': main() xappy-0.5/testsuite/unittests/spell_correct_1.py0000644000175000017500000000210710711422250022050 0ustar richardrichardfrom unittest import TestCase, main import tempfile, os, sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../..')) from xappy.indexerconnection import * from xappy.fieldactions import * from xappy.searchconnection import * class TestSpellCorrect(TestCase): def setUp(self): tempdir = tempfile.mkdtemp() self.indexpath = os.path.join(tempdir, 'foo') iconn = IndexerConnection(self.indexpath) iconn.add_field_action('name', FieldActions.INDEX_FREETEXT, spell=True,) for i in xrange(5): doc = UnprocessedDocument() doc.fields.append(Field('name', 'bruno is a nice guy')) iconn.add(doc) iconn.flush() iconn.close() self.sconn = SearchConnection(self.indexpath) def test_spell_correct(self): query = 'brunore' self.assertEqual('bruno', self.sconn.spell_correct(query)) query = 'brunore-brunore' self.sconn.spell_correct(query)#will throw RuntimeError def tearDown(self): self.sconn.close() if __name__ == '__main__': main() xappy-0.5/testsuite/coverage.py0000755000175000017500000012357710677214601016555 0ustar richardrichard#!/usr/bin/python # # Perforce Defect Tracking Integration Project # # # COVERAGE.PY -- COVERAGE TESTING # # Gareth Rees, Ravenbrook Limited, 2001-12-04 # Ned Batchelder, 2004-12-12 # http://nedbatchelder.com/code/modules/coverage.html # # # 1. INTRODUCTION # # This module provides coverage testing for Python code. # # The intended readership is all Python developers. # # This document is not confidential. # # See [GDR 2001-12-04a] for the command-line interface, programmatic # interface and limitations. See [GDR 2001-12-04b] for requirements and # design. r"""Usage: coverage.py -x [-p] MODULE.py [ARG1 ARG2 ...] Execute module, passing the given command-line arguments, collecting coverage data. With the -p option, write to a temporary file containing the machine name and process ID. coverage.py -e Erase collected coverage data. coverage.py -c Collect data from multiple coverage files (as created by -p option above) and store it into a single file representing the union of the coverage. coverage.py -r [-m] [-o dir1,dir2,...] FILE1 FILE2 ... Report on the statement coverage for the given files. With the -m option, show line numbers of the statements that weren't executed. coverage.py -a [-d dir] [-o dir1,dir2,...] FILE1 FILE2 ... Make annotated copies of the given files, marking statements that are executed with > and statements that are missed with !. With the -d option, make the copies in that directory. Without the -d option, make each copy in the same directory as the original. -o dir,dir2,... Omit reporting or annotating files when their filename path starts with a directory listed in the omit list. e.g. python coverage.py -i -r -o c:\python23,lib\enthought\traits Coverage data is saved in the file .coverage by default. Set the COVERAGE_FILE environment variable to save it somewhere else.""" __version__ = "2.77.20070729" # see detailed history at the end of this file. import compiler import compiler.visitor import glob import os import re import string import symbol import sys import threading import token import types from socket import gethostname # Python version compatibility try: strclass = basestring # new to 2.3 except: strclass = str import doctest # # Doctest and coverage both need to hook into the debugger, and if we don't do # special handling, doctest tends to take over and cause coverage not to see # lines which are executed. Note that this handling is only needed if doctest # is used, but we do it anyway because that's simplest. # # This patch is based on this changeset in nose: # http://nose.python-hosting.com/changeset/133 # # which is in turn based on this patch from Zope: # # zope patch: # http://svn.zope.org/Zope3/trunk/src/zope/testing/doctest.py?rev=28679&r1=28703&r2=28705 # _orp = doctest._OutputRedirectingPdb class CoverageOutputRedirectingPdb(_orp): def __init__(self, out): self.__debugger_used = False _orp.__init__(self, out) def set_trace(self): self.__debugger_used = True _orp.set_trace(self) def set_continue(self): # Calling set_continue unconditionally would break unit test coverage # reporting, as Bdb.set_continue calls sys.settrace(None). if self.__debugger_used: _orp.set_continue(self) doctest._OutputRedirectingPdb = CoverageOutputRedirectingPdb # 2. IMPLEMENTATION # # This uses the "singleton" pattern. # # The word "morf" means a module object (from which the source file can # be deduced by suitable manipulation of the __file__ attribute) or a # filename. # # When we generate a coverage report we have to canonicalize every # filename in the coverage dictionary just in case it refers to the # module we are reporting on. It seems a shame to throw away this # information so the data in the coverage dictionary is transferred to # the 'cexecuted' dictionary under the canonical filenames. # # The coverage dictionary is called "c" and the trace function "t". The # reason for these short names is that Python looks up variables by name # at runtime and so execution time depends on the length of variables! # In the bottleneck of this application it's appropriate to abbreviate # names to increase speed. class StatementFindingAstVisitor(compiler.visitor.ASTVisitor): """ A visitor for a parsed Abstract Syntax Tree which finds executable statements. """ def __init__(self, statements, excluded, suite_spots): compiler.visitor.ASTVisitor.__init__(self) self.statements = statements self.excluded = excluded self.suite_spots = suite_spots self.excluding_suite = 0 def doRecursive(self, node): for n in node.getChildNodes(): self.dispatch(n) visitStmt = visitModule = doRecursive def doCode(self, node): if hasattr(node, 'decorators') and node.decorators: self.dispatch(node.decorators) self.recordAndDispatch(node.code) else: self.doSuite(node, node.code) visitFunction = visitClass = doCode def getFirstLine(self, node): # Find the first line in the tree node. lineno = node.lineno for n in node.getChildNodes(): f = self.getFirstLine(n) if lineno and f: lineno = min(lineno, f) else: lineno = lineno or f return lineno def getLastLine(self, node): # Find the first line in the tree node. lineno = node.lineno for n in node.getChildNodes(): lineno = max(lineno, self.getLastLine(n)) return lineno def doStatement(self, node): self.recordLine(self.getFirstLine(node)) visitAssert = visitAssign = visitAssTuple = visitPrint = \ visitPrintnl = visitRaise = visitSubscript = visitDecorators = \ doStatement def visitPass(self, node): # Pass statements have weird interactions with docstrings. If this # pass statement is part of one of those pairs, claim that the statement # is on the later of the two lines. l = node.lineno if l: lines = self.suite_spots.get(l, [l,l]) self.statements[lines[1]] = 1 def visitDiscard(self, node): # Discard nodes are statements that execute an expression, but then # discard the results. This includes function calls, so we can't # ignore them all. But if the expression is a constant, the statement # won't be "executed", so don't count it now. if node.expr.__class__.__name__ != 'Const': self.doStatement(node) def recordNodeLine(self, node): # Stmt nodes often have None, but shouldn't claim the first line of # their children (because the first child might be an ignorable line # like "global a"). if node.__class__.__name__ != 'Stmt': return self.recordLine(self.getFirstLine(node)) else: return 0 def recordLine(self, lineno): # Returns a bool, whether the line is included or excluded. if lineno: # Multi-line tests introducing suites have to get charged to their # keyword. if lineno in self.suite_spots: lineno = self.suite_spots[lineno][0] # If we're inside an excluded suite, record that this line was # excluded. if self.excluding_suite: self.excluded[lineno] = 1 return 0 # If this line is excluded, or suite_spots maps this line to # another line that is exlcuded, then we're excluded. elif self.excluded.has_key(lineno) or \ self.suite_spots.has_key(lineno) and \ self.excluded.has_key(self.suite_spots[lineno][1]): return 0 # Otherwise, this is an executable line. else: self.statements[lineno] = 1 return 1 return 0 default = recordNodeLine def recordAndDispatch(self, node): self.recordNodeLine(node) self.dispatch(node) def doSuite(self, intro, body, exclude=0): exsuite = self.excluding_suite if exclude or (intro and not self.recordNodeLine(intro)): self.excluding_suite = 1 self.recordAndDispatch(body) self.excluding_suite = exsuite def doPlainWordSuite(self, prevsuite, suite): # Finding the exclude lines for else's is tricky, because they aren't # present in the compiler parse tree. Look at the previous suite, # and find its last line. If any line between there and the else's # first line are excluded, then we exclude the else. lastprev = self.getLastLine(prevsuite) firstelse = self.getFirstLine(suite) for l in range(lastprev+1, firstelse): if self.suite_spots.has_key(l): self.doSuite(None, suite, exclude=self.excluded.has_key(l)) break else: self.doSuite(None, suite) def doElse(self, prevsuite, node): if node.else_: self.doPlainWordSuite(prevsuite, node.else_) def visitFor(self, node): self.doSuite(node, node.body) self.doElse(node.body, node) visitWhile = visitFor def visitIf(self, node): # The first test has to be handled separately from the rest. # The first test is credited to the line with the "if", but the others # are credited to the line with the test for the elif. self.doSuite(node, node.tests[0][1]) for t, n in node.tests[1:]: self.doSuite(t, n) self.doElse(node.tests[-1][1], node) def visitTryExcept(self, node): self.doSuite(node, node.body) for i in range(len(node.handlers)): a, b, h = node.handlers[i] if not a: # It's a plain "except:". Find the previous suite. if i > 0: prev = node.handlers[i-1][2] else: prev = node.body self.doPlainWordSuite(prev, h) else: self.doSuite(a, h) self.doElse(node.handlers[-1][2], node) def visitTryFinally(self, node): self.doSuite(node, node.body) self.doPlainWordSuite(node.body, node.final) def visitWith(self, node): self.doSuite(node, node.body) def visitGlobal(self, node): # "global" statements don't execute like others (they don't call the # trace function), so don't record their line numbers. pass the_coverage = None class CoverageException(Exception): pass class coverage: # Name of the cache file (unless environment variable is set). cache_default = ".coverage" # Environment variable naming the cache file. cache_env = "COVERAGE_FILE" # A dictionary with an entry for (Python source file name, line number # in that file) if that line has been executed. c = {} # A map from canonical Python source file name to a dictionary in # which there's an entry for each line number that has been # executed. cexecuted = {} # Cache of results of calling the analysis2() method, so that you can # specify both -r and -a without doing double work. analysis_cache = {} # Cache of results of calling the canonical_filename() method, to # avoid duplicating work. canonical_filename_cache = {} def __init__(self): global the_coverage if the_coverage: raise CoverageException, "Only one coverage object allowed." self.usecache = 1 self.cache = None self.clear_cache = False self.parallel_mode = False self.exclude_re = '' self.nesting = 0 self.cstack = [] self.xstack = [] self.relative_dir = os.path.normcase(os.path.abspath(os.curdir)+os.sep) self.exclude('# *pragma[: ]*[nN][oO] *[cC][oO][vV][eE][rR]') # t(f, x, y). This method is passed to sys.settrace as a trace function. # See [van Rossum 2001-07-20b, 9.2] for an explanation of sys.settrace and # the arguments and return value of the trace function. # See [van Rossum 2001-07-20a, 3.2] for a description of frame and code # objects. def t(self, f, w, unused): #pragma: no cover if w == 'line': #print "Executing %s @ %d" % (f.f_code.co_filename, f.f_lineno) self.c[(f.f_code.co_filename, f.f_lineno)] = 1 for c in self.cstack: c[(f.f_code.co_filename, f.f_lineno)] = 1 return self.t def help(self, error=None): #pragma: no cover if error: print error print print __doc__ sys.exit(1) def command_line(self, argv, help_fn=None): import getopt help_fn = help_fn or self.help settings = {} optmap = { '-a': 'annotate', '-c': 'collect', '-d:': 'directory=', '-e': 'erase', '-h': 'help', '-i': 'ignore-errors', '-m': 'show-missing', '-p': 'parallel-mode', '-r': 'report', '-x': 'execute', '-o:': 'omit=', } short_opts = string.join(map(lambda o: o[1:], optmap.keys()), '') long_opts = optmap.values() options, args = getopt.getopt(argv, short_opts, long_opts) for o, a in options: if optmap.has_key(o): settings[optmap[o]] = 1 elif optmap.has_key(o + ':'): settings[optmap[o + ':']] = a elif o[2:] in long_opts: settings[o[2:]] = 1 elif o[2:] + '=' in long_opts: settings[o[2:]+'='] = a else: #pragma: no cover pass # Can't get here, because getopt won't return anything unknown. if settings.get('help'): help_fn() for i in ['erase', 'execute']: for j in ['annotate', 'report', 'collect']: if settings.get(i) and settings.get(j): help_fn("You can't specify the '%s' and '%s' " "options at the same time." % (i, j)) args_needed = (settings.get('execute') or settings.get('annotate') or settings.get('report')) action = (settings.get('erase') or settings.get('collect') or args_needed) if not action: help_fn("You must specify at least one of -e, -x, -c, -r, or -a.") if not args_needed and args: help_fn("Unexpected arguments: %s" % " ".join(args)) self.parallel_mode = settings.get('parallel-mode') self.get_ready() if settings.get('erase'): self.erase() if settings.get('execute'): if not args: help_fn("Nothing to do.") sys.argv = args self.start() import __main__ sys.path[0] = os.path.dirname(sys.argv[0]) execfile(sys.argv[0], __main__.__dict__) if settings.get('collect'): self.collect() if not args: args = self.cexecuted.keys() ignore_errors = settings.get('ignore-errors') show_missing = settings.get('show-missing') directory = settings.get('directory=') omit = settings.get('omit=') if omit is not None: omit = omit.split(',') else: omit = [] if settings.get('report'): self.report(args, show_missing, ignore_errors, omit_prefixes=omit) if settings.get('annotate'): self.annotate(args, directory, ignore_errors, omit_prefixes=omit) def use_cache(self, usecache, cache_file=None): self.usecache = usecache if cache_file and not self.cache: self.cache_default = cache_file def get_ready(self, parallel_mode=False): if self.usecache and not self.cache: self.cache = os.environ.get(self.cache_env, self.cache_default) if self.parallel_mode: self.cache += "." + gethostname() + "." + str(os.getpid()) if self.clear_cache: try: os.remove(self.cache) except OSError: pass self.restore() self.analysis_cache = {} def start(self, parallel_mode=False): self.get_ready() if self.nesting == 0: #pragma: no cover sys.settrace(self.t) if hasattr(threading, 'settrace'): threading.settrace(self.t) self.nesting += 1 def stop(self): self.nesting -= 1 if self.nesting == 0: #pragma: no cover sys.settrace(None) if hasattr(threading, 'settrace'): threading.settrace(None) def erase(self): self.get_ready() self.c = {} self.analysis_cache = {} self.cexecuted = {} if self.cache and os.path.exists(self.cache): os.remove(self.cache) self.clear_cache = True self.exclude_re = "" def exclude(self, re): if self.exclude_re: self.exclude_re += "|" self.exclude_re += "(" + re + ")" def begin_recursive(self): self.cstack.append(self.c) self.xstack.append(self.exclude_re) def end_recursive(self): self.c = self.cstack.pop() self.exclude_re = self.xstack.pop() # save(). Save coverage data to the coverage cache. def save(self): if self.usecache and self.cache: self.canonicalize_filenames() cache = open(self.cache, 'wb') import marshal marshal.dump(self.cexecuted, cache) cache.close() # restore(). Restore coverage data from the coverage cache (if it exists). def restore(self): self.c = {} self.cexecuted = {} assert self.usecache if os.path.exists(self.cache): self.cexecuted = self.restore_file(self.cache) def restore_file(self, file_name): try: cache = open(file_name, 'rb') import marshal cexecuted = marshal.load(cache) cache.close() if isinstance(cexecuted, types.DictType): return cexecuted else: return {} except: return {} # collect(). Collect data in multiple files produced by parallel mode def collect(self): cache_dir, local = os.path.split(self.cache) for f in os.listdir(cache_dir or '.'): if not f.startswith(local): continue full_path = os.path.join(cache_dir, f) cexecuted = self.restore_file(full_path) self.merge_data(cexecuted) def merge_data(self, new_data): for file_name, file_data in new_data.items(): if self.cexecuted.has_key(file_name): self.merge_file_data(self.cexecuted[file_name], file_data) else: self.cexecuted[file_name] = file_data def merge_file_data(self, cache_data, new_data): for line_number in new_data.keys(): if not cache_data.has_key(line_number): cache_data[line_number] = new_data[line_number] # canonical_filename(filename). Return a canonical filename for the # file (that is, an absolute path with no redundant components and # normalized case). See [GDR 2001-12-04b, 3.3]. def canonical_filename(self, filename): if not self.canonical_filename_cache.has_key(filename): f = filename if os.path.isabs(f) and not os.path.exists(f): f = os.path.basename(f) if not os.path.isabs(f): for path in [os.curdir] + sys.path: g = os.path.join(path, f) if os.path.exists(g): f = g break cf = os.path.normcase(os.path.abspath(f)) self.canonical_filename_cache[filename] = cf return self.canonical_filename_cache[filename] # canonicalize_filenames(). Copy results from "c" to "cexecuted", # canonicalizing filenames on the way. Clear the "c" map. def canonicalize_filenames(self): for filename, lineno in self.c.keys(): if filename == '': # Can't do anything useful with exec'd strings, so skip them. continue f = self.canonical_filename(filename) if not self.cexecuted.has_key(f): self.cexecuted[f] = {} self.cexecuted[f][lineno] = 1 self.c = {} # morf_filename(morf). Return the filename for a module or file. def morf_filename(self, morf): if isinstance(morf, types.ModuleType): if not hasattr(morf, '__file__'): raise CoverageException, "Module has no __file__ attribute." f = morf.__file__ else: f = morf return self.canonical_filename(f) # analyze_morf(morf). Analyze the module or filename passed as # the argument. If the source code can't be found, raise an error. # Otherwise, return a tuple of (1) the canonical filename of the # source code for the module, (2) a list of lines of statements # in the source code, (3) a list of lines of excluded statements, # and (4), a map of line numbers to multi-line line number ranges, for # statements that cross lines. def analyze_morf(self, morf): if self.analysis_cache.has_key(morf): return self.analysis_cache[morf] filename = self.morf_filename(morf) ext = os.path.splitext(filename)[1] if ext == '.pyc': if not os.path.exists(filename[0:-1]): raise CoverageException, ("No source for compiled code '%s'." % filename) filename = filename[0:-1] elif ext != '.py': raise CoverageException, "File '%s' not Python source." % filename source = open(filename, 'r') lines, excluded_lines, line_map = self.find_executable_statements( source.read(), exclude=self.exclude_re ) source.close() result = filename, lines, excluded_lines, line_map self.analysis_cache[morf] = result return result def first_line_of_tree(self, tree): while True: if len(tree) == 3 and type(tree[2]) == type(1): return tree[2] tree = tree[1] def last_line_of_tree(self, tree): while True: if len(tree) == 3 and type(tree[2]) == type(1): return tree[2] tree = tree[-1] def find_docstring_pass_pair(self, tree, spots): for i in range(1, len(tree)): if self.is_string_constant(tree[i]) and self.is_pass_stmt(tree[i+1]): first_line = self.first_line_of_tree(tree[i]) last_line = self.last_line_of_tree(tree[i+1]) self.record_multiline(spots, first_line, last_line) def is_string_constant(self, tree): try: return tree[0] == symbol.stmt and tree[1][1][1][0] == symbol.expr_stmt except: return False def is_pass_stmt(self, tree): try: return tree[0] == symbol.stmt and tree[1][1][1][0] == symbol.pass_stmt except: return False def record_multiline(self, spots, i, j): for l in range(i, j+1): spots[l] = (i, j) def get_suite_spots(self, tree, spots): """ Analyze a parse tree to find suite introducers which span a number of lines. """ for i in range(1, len(tree)): if type(tree[i]) == type(()): if tree[i][0] == symbol.suite: # Found a suite, look back for the colon and keyword. lineno_colon = lineno_word = None for j in range(i-1, 0, -1): if tree[j][0] == token.COLON: # Colons are never executed themselves: we want the # line number of the last token before the colon. lineno_colon = self.last_line_of_tree(tree[j-1]) elif tree[j][0] == token.NAME: if tree[j][1] == 'elif': # Find the line number of the first non-terminal # after the keyword. t = tree[j+1] while t and token.ISNONTERMINAL(t[0]): t = t[1] if t: lineno_word = t[2] else: lineno_word = tree[j][2] break elif tree[j][0] == symbol.except_clause: # "except" clauses look like: # ('except_clause', ('NAME', 'except', lineno), ...) if tree[j][1][0] == token.NAME: lineno_word = tree[j][1][2] break if lineno_colon and lineno_word: # Found colon and keyword, mark all the lines # between the two with the two line numbers. self.record_multiline(spots, lineno_word, lineno_colon) # "pass" statements are tricky: different versions of Python # treat them differently, especially in the common case of a # function with a doc string and a single pass statement. self.find_docstring_pass_pair(tree[i], spots) elif tree[i][0] == symbol.simple_stmt: first_line = self.first_line_of_tree(tree[i]) last_line = self.last_line_of_tree(tree[i]) if first_line != last_line: self.record_multiline(spots, first_line, last_line) self.get_suite_spots(tree[i], spots) def find_executable_statements(self, text, exclude=None): # Find lines which match an exclusion pattern. excluded = {} suite_spots = {} if exclude: reExclude = re.compile(exclude) lines = text.split('\n') for i in range(len(lines)): if reExclude.search(lines[i]): excluded[i+1] = 1 # Parse the code and analyze the parse tree to find out which statements # are multiline, and where suites begin and end. import parser tree = parser.suite(text+'\n\n').totuple(1) self.get_suite_spots(tree, suite_spots) #print "Suite spots:", suite_spots # Use the compiler module to parse the text and find the executable # statements. We add newlines to be impervious to final partial lines. statements = {} ast = compiler.parse(text+'\n\n') visitor = StatementFindingAstVisitor(statements, excluded, suite_spots) compiler.walk(ast, visitor, walker=visitor) lines = statements.keys() lines.sort() excluded_lines = excluded.keys() excluded_lines.sort() return lines, excluded_lines, suite_spots # format_lines(statements, lines). Format a list of line numbers # for printing by coalescing groups of lines as long as the lines # represent consecutive statements. This will coalesce even if # there are gaps between statements, so if statements = # [1,2,3,4,5,10,11,12,13,14] and lines = [1,2,5,10,11,13,14] then # format_lines will return "1-2, 5-11, 13-14". def format_lines(self, statements, lines): pairs = [] i = 0 j = 0 start = None pairs = [] while i < len(statements) and j < len(lines): if statements[i] == lines[j]: if start == None: start = lines[j] end = lines[j] j = j + 1 elif start: pairs.append((start, end)) start = None i = i + 1 if start: pairs.append((start, end)) def stringify(pair): start, end = pair if start == end: return "%d" % start else: return "%d-%d" % (start, end) ret = string.join(map(stringify, pairs), ", ") return ret # Backward compatibility with version 1. def analysis(self, morf): f, s, _, m, mf = self.analysis2(morf) return f, s, m, mf def analysis2(self, morf): filename, statements, excluded, line_map = self.analyze_morf(morf) self.canonicalize_filenames() if not self.cexecuted.has_key(filename): self.cexecuted[filename] = {} missing = [] for line in statements: lines = line_map.get(line, [line, line]) for l in range(lines[0], lines[1]+1): if self.cexecuted[filename].has_key(l): break else: missing.append(line) return (filename, statements, excluded, missing, self.format_lines(statements, missing)) def relative_filename(self, filename): """ Convert filename to relative filename from self.relative_dir. """ return filename.replace(self.relative_dir, "") def morf_name(self, morf): """ Return the name of morf as used in report. """ if isinstance(morf, types.ModuleType): return morf.__name__ else: return self.relative_filename(os.path.splitext(morf)[0]) def filter_by_prefix(self, morfs, omit_prefixes): """ Return list of morfs where the morf name does not begin with any one of the omit_prefixes. """ filtered_morfs = [] for morf in morfs: for prefix in omit_prefixes: if self.morf_name(morf).startswith(prefix): break else: filtered_morfs.append(morf) return filtered_morfs def morf_name_compare(self, x, y): return cmp(self.morf_name(x), self.morf_name(y)) def report(self, morfs, show_missing=1, ignore_errors=0, file=None, omit_prefixes=[]): if not isinstance(morfs, types.ListType): morfs = [morfs] # On windows, the shell doesn't expand wildcards. Do it here. globbed = [] for morf in morfs: if isinstance(morf, strclass): globbed.extend(glob.glob(morf)) else: globbed.append(morf) morfs = globbed morfs = self.filter_by_prefix(morfs, omit_prefixes) morfs.sort(self.morf_name_compare) max_name = max([5,] + map(len, map(self.morf_name, morfs))) fmt_name = "%%- %ds " % max_name fmt_err = fmt_name + "%s: %s" header = fmt_name % "Name" + " Stmts Exec Cover" fmt_coverage = fmt_name + "% 6d % 6d % 5d%%" if show_missing: header = header + " Missing" fmt_coverage = fmt_coverage + " %s" if not file: file = sys.stdout print >>file, header print >>file, "-" * len(header) total_statements = 0 total_executed = 0 for morf in morfs: name = self.morf_name(morf) try: _, statements, _, missing, readable = self.analysis2(morf) n = len(statements) m = n - len(missing) if n > 0: pc = 100.0 * m / n else: pc = 100.0 args = (name, n, m, pc) if show_missing: args = args + (readable,) print >>file, fmt_coverage % args total_statements = total_statements + n total_executed = total_executed + m except KeyboardInterrupt: #pragma: no cover raise except: if not ignore_errors: typ, msg = sys.exc_info()[0:2] print >>file, fmt_err % (name, typ, msg) if len(morfs) > 1: print >>file, "-" * len(header) if total_statements > 0: pc = 100.0 * total_executed / total_statements else: pc = 100.0 args = ("TOTAL", total_statements, total_executed, pc) if show_missing: args = args + ("",) print >>file, fmt_coverage % args # annotate(morfs, ignore_errors). blank_re = re.compile(r"\s*(#|$)") else_re = re.compile(r"\s*else\s*:\s*(#|$)") def annotate(self, morfs, directory=None, ignore_errors=0, omit_prefixes=[]): morfs = self.filter_by_prefix(morfs, omit_prefixes) for morf in morfs: try: filename, statements, excluded, missing, _ = self.analysis2(morf) self.annotate_file(filename, statements, excluded, missing, directory) except KeyboardInterrupt: raise except: if not ignore_errors: raise def annotate_file(self, filename, statements, excluded, missing, directory=None): source = open(filename, 'r') if directory: dest_file = os.path.join(directory, os.path.basename(filename) + ',cover') else: dest_file = filename + ',cover' dest = open(dest_file, 'w') lineno = 0 i = 0 j = 0 covered = 1 while 1: line = source.readline() if line == '': break lineno = lineno + 1 while i < len(statements) and statements[i] < lineno: i = i + 1 while j < len(missing) and missing[j] < lineno: j = j + 1 if i < len(statements) and statements[i] == lineno: covered = j >= len(missing) or missing[j] > lineno if self.blank_re.match(line): dest.write(' ') elif self.else_re.match(line): # Special logic for lines containing only 'else:'. # See [GDR 2001-12-04b, 3.2]. if i >= len(statements) and j >= len(missing): dest.write('! ') elif i >= len(statements) or j >= len(missing): dest.write('> ') elif statements[i] == missing[j]: dest.write('! ') else: dest.write('> ') elif lineno in excluded: dest.write('- ') elif covered: dest.write('> ') else: dest.write('! ') dest.write(line) source.close() dest.close() # Singleton object. the_coverage = coverage() # Module functions call methods in the singleton object. def use_cache(*args, **kw): return the_coverage.use_cache(*args, **kw) def start(*args, **kw): return the_coverage.start(*args, **kw) def stop(*args, **kw): return the_coverage.stop(*args, **kw) def erase(*args, **kw): return the_coverage.erase(*args, **kw) def begin_recursive(*args, **kw): return the_coverage.begin_recursive(*args, **kw) def end_recursive(*args, **kw): return the_coverage.end_recursive(*args, **kw) def exclude(*args, **kw): return the_coverage.exclude(*args, **kw) def analysis(*args, **kw): return the_coverage.analysis(*args, **kw) def analysis2(*args, **kw): return the_coverage.analysis2(*args, **kw) def report(*args, **kw): return the_coverage.report(*args, **kw) def annotate(*args, **kw): return the_coverage.annotate(*args, **kw) def annotate_file(*args, **kw): return the_coverage.annotate_file(*args, **kw) # Save coverage data when Python exits. (The atexit module wasn't # introduced until Python 2.0, so use sys.exitfunc when it's not # available.) try: import atexit atexit.register(the_coverage.save) except ImportError: sys.exitfunc = the_coverage.save # Command-line interface. if __name__ == '__main__': the_coverage.command_line(sys.argv[1:]) # A. REFERENCES # # [GDR 2001-12-04a] "Statement coverage for Python"; Gareth Rees; # Ravenbrook Limited; 2001-12-04; # . # # [GDR 2001-12-04b] "Statement coverage for Python: design and # analysis"; Gareth Rees; Ravenbrook Limited; 2001-12-04; # . # # [van Rossum 2001-07-20a] "Python Reference Manual (releae 2.1.1)"; # Guide van Rossum; 2001-07-20; # . # # [van Rossum 2001-07-20b] "Python Library Reference"; Guido van Rossum; # 2001-07-20; . # # # B. DOCUMENT HISTORY # # 2001-12-04 GDR Created. # # 2001-12-06 GDR Added command-line interface and source code # annotation. # # 2001-12-09 GDR Moved design and interface to separate documents. # # 2001-12-10 GDR Open cache file as binary on Windows. Allow # simultaneous -e and -x, or -a and -r. # # 2001-12-12 GDR Added command-line help. Cache analysis so that it # only needs to be done once when you specify -a and -r. # # 2001-12-13 GDR Improved speed while recording. Portable between # Python 1.5.2 and 2.1.1. # # 2002-01-03 GDR Module-level functions work correctly. # # 2002-01-07 GDR Update sys.path when running a file with the -x option, # so that it matches the value the program would get if it were run on # its own. # # 2004-12-12 NMB Significant code changes. # - Finding executable statements has been rewritten so that docstrings and # other quirks of Python execution aren't mistakenly identified as missing # lines. # - Lines can be excluded from consideration, even entire suites of lines. # - The filesystem cache of covered lines can be disabled programmatically. # - Modernized the code. # # 2004-12-14 NMB Minor tweaks. Return 'analysis' to its original behavior # and add 'analysis2'. Add a global for 'annotate', and factor it, adding # 'annotate_file'. # # 2004-12-31 NMB Allow for keyword arguments in the module global functions. # Thanks, Allen. # # 2005-12-02 NMB Call threading.settrace so that all threads are measured. # Thanks Martin Fuzzey. Add a file argument to report so that reports can be # captured to a different destination. # # 2005-12-03 NMB coverage.py can now measure itself. # # 2005-12-04 NMB Adapted Greg Rogers' patch for using relative filenames, # and sorting and omitting files to report on. # # 2006-07-23 NMB Applied Joseph Tate's patch for function decorators. # # 2006-08-21 NMB Applied Sigve Tjora and Mark van der Wal's fixes for argument # handling. # # 2006-08-22 NMB Applied Geoff Bache's parallel mode patch. # # 2006-08-23 NMB Refactorings to improve testability. Fixes to command-line # logic for parallel mode and collect. # # 2006-08-25 NMB "#pragma: nocover" is excluded by default. # # 2006-09-10 NMB Properly ignore docstrings and other constant expressions that # appear in the middle of a function, a problem reported by Tim Leslie. # Minor changes to avoid lint warnings. # # 2006-09-17 NMB coverage.erase() shouldn't clobber the exclude regex. # Change how parallel mode is invoked, and fix erase() so that it erases the # cache when called programmatically. # # 2007-07-21 NMB In reports, ignore code executed from strings, since we can't # do anything useful with it anyway. # Better file handling on Linux, thanks Guillaume Chazarain. # Better shell support on Windows, thanks Noel O'Boyle. # Python 2.2 support maintained, thanks Catherine Proulx. # # 2007-07-22 NMB Python 2.5 now fully supported. The method of dealing with # multi-line statements is now less sensitive to the exact line that Python # reports during execution. Pass statements are handled specially so that their # disappearance during execution won't throw off the measurement. # # 2007-07-23 NMB Now Python 2.5 is *really* fully supported: the body of the # new with statement is counted as executable. # # 2007-07-29 NMB Better packaging. # C. COPYRIGHT AND LICENCE # # Copyright 2001 Gareth Rees. All rights reserved. # Copyright 2004-2007 Ned Batchelder. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. 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 # HOLDERS AND 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. # # $Id: coverage.py 74 2007-07-29 22:28:35Z nedbat $ xappy-0.5/testsuite/runtests.py0000755000175000017500000002665411004346430016636 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""runtests.py: Run a set of tests with doctest and unittest. The list of modules to test is specified at the top of the file, in the MODNAMES variable. Other files containing documentation to be tested is listed in the OTHER_FILES variable. A subset of the modules can be tested by specifying a list of module names on the command line. """ __docformat__ = "restructuredtext en" ####################### # Begin configuration # ####################### # List the modules to test with doctest (please keep this list in alphabetical # order, for ease of maintenance). MODNAMES = ( 'secore', 'secore.datastructures', 'secore.errors', 'secore.fieldactions', 'secore.fieldmappings', 'secore.highlight', 'secore.indexerconnection', 'secore.marshall', 'secore.parsedate', 'secore.searchconnection', 'xappy', 'xappy.datastructures', 'xappy.errors', 'xappy.fieldactions', 'xappy.fieldmappings', 'xappy.highlight', 'xappy.indexerconnection', 'xappy.marshall', 'xappy.parsedate', 'xappy.searchconnection', ) # List the documentation files which should be valid doctest inputs OTHER_FILES = ( 'docs/introduction.rst', ) # Whitelist lines for coverage report (ie, lines which should always be # considered as having been executed). The first item in each line is a line # number that the line can appear at, which may be negative to indicate lines # from the end of the file. The second item is a regular expression to match # against the line: if the expression matches, the line will be considered # executed. COVERED_LINES = ( (-2, r'\s*import doctest, sys'), (-1, r'\s*doctest.testmod'), ) ######################## # End of configuration # ######################## import sys import os import re import unittest import doctest import traceback import copy def canonical_path(path): return os.path.normcase(os.path.normpath(os.path.realpath(path))) def check_whitelist(lines, checklinenum, covered_lines): """Check whether line `checklinenum`, for the file with contents `lines` is in the whitelist. Return True if so, False otherwise. """ for linenum, pattern in covered_lines: if linenum < 0: linenum += len(lines) + 1 if linenum <= 0 or linenum > len(lines): continue if checklinenum != linenum: continue if not pattern.match(lines[checklinenum - 1]): continue return True return False def create_docfile_suite(mod, modpath): """Create a suite of tests from a text file containing doctests. The dictionary of the module is imported into the namespace which the tests are run in (excluding any entries which begin with a double underscore), so the tests can be written as if they were entries in the modules __test__ dictionary. """ globs = {'__file__': modpath, } for key in mod.__dict__.keys(): if not key.startswith('__'): globs[key] = mod.__dict__[key] return doctest.DocFileSuite(modpath, module_relative=False, globs=globs, setUp=setup_test, tearDown=teardown_test, ) def recursive_rm(path): """Recursively remove a directory and its contents. """ if os.path.isdir(path): for root, dirs, files in os.walk(path, topdown=False): for file in files: os.remove(os.path.join(root, file)) for dir in dirs: os.rmdir(os.path.join(root, dir)) os.rmdir(path) _orig_vals = {} def setup_test(dtobj): """Prepare for running a test. """ tmpdir = 'test_tmp' recursive_rm(tmpdir) _orig_vals['wd'] = os.path.abspath(os.getcwd()) _orig_vals['path'] = sys.path sys.path = copy.copy(sys.path) sys.path.insert(0, _orig_vals['wd']) testdir = os.path.dirname(dtobj.globs['__file__']) sys.path.insert(0, testdir) os.mkdir(tmpdir) os.chdir(tmpdir) def teardown_test(dtobj): """Cleanup after running a test. """ for key, val in list(dtobj.globs.iteritems()): if hasattr(val, '__module__') and \ val.__module__ is not None and \ val.__module__.startswith('xappy'): if hasattr(val, 'close'): if not isinstance(val, type): val.close() del dtobj.globs[key] del key del val dtobj.globs.clear() # Try really hard to make sure any xapian databases have been closed # properly, so that windows doesn't give errors when we try and delete # them. import gc gc.collect() tmpdir = 'test_tmp' os.chdir(_orig_vals['wd']) sys.path = _orig_vals['path'] recursive_rm(tmpdir) def run_tests(topdir, modnames, other_files, use_coverage): """Run tests on the specified modules. Returns a list of modules which were tested. """ # Check command line for overrides to module names if len(sys.argv) > 1: newnames = [] for arg in sys.argv[1:]: if arg in modnames: newnames.append(arg) else: print "Module `%s' not known" % arg sys.exit(1) modnames = newnames # Make a test suite to put all the tests in. suite = unittest.TestSuite() if use_coverage: # Use the coverage test module to get coverage information. import coverage coverage.erase() coverage.start() coverage.exclude('#pragma[: ]+[nN][oO] [cC][oO][vV][eE][rR]') # Add all the doctest tests. modules = [] for modname in modnames: try: # Get the path of the module (to search for associated tests) modpath = os.path.join(*(modname.split('.'))) modpath = canonical_path(modpath) if os.path.isdir(modpath): modpath = os.path.join(modpath, '__init__') # Import the module sys.path.insert(0, topdir) mod = __import__(modname, None, None, ['']) del sys.path[0] # Check that the module imported came from the expected path. if os.path.splitext(mod.__file__)[0] != modpath: print "Couldn't import module `%s`: got module of same name, from wrong path (%r)" % (modname, mod.__file__) continue # Add module to test suite. suite.addTest(doctest.DocTestSuite(mod, setUp=setup_test, tearDown=teardown_test)) modules.append(mod) # Check for additional doctest files modpath = modpath + '_doctest%d.txt' num = 1 while os.path.exists(modpath % num): suite.addTest(create_docfile_suite(mod, modpath % num)) num += 1 except ImportError, e: print "Couldn't import module `%s`: %s" % (modname, e) traceback.print_exc() # Add any other files with doctests in them. for file in other_files: fullpath = os.path.join(topdir, file) globs = {'__file__': os.path.join(canonical_path("xappy"), '__init__'),} suite.addTest(doctest.DocFileSuite(fullpath, module_relative=False, globs=globs, setUp=setup_test, tearDown=teardown_test, )) # Now, run everything. runner = unittest.TextTestRunner() runner.run(suite) if use_coverage: # Finished run - stop the coverage tests coverage.stop() return modules def get_coverage(topdir, modules, covered_lines): import coverage # Compile the expressions in COVERED_LINES covered_lines = [(lines, re.compile(pattern)) for (lines, pattern) in covered_lines] # Get the coverage statistics stats = [] for module in modules: (filename, stmtlines, stmtmissed, stmtmissed_desc) = coverage.analysis(module) filename = canonical_path(filename) if filename.startswith(topdir): filename = filename[len(topdir) + 1:] lines = open(filename).readlines() linenum = len(lines) # Remove whitelisted lines stmtmissed = [linenum for linenum in stmtmissed if not check_whitelist(lines, linenum, covered_lines)] # Sort the lines (probably already in order, but let's double-check) stmtlines.sort() stmtmissed.sort() # Build a compressed list of ranges of lines which have no statements # which were executed, but do contain statements. missed_ranges = [] stmtpos = 0 currrange = None for linenum in stmtmissed: while stmtlines[stmtpos] < linenum: # If there are any statements before the current linenum, we # end the current range of missed statements currrange = None stmtpos += 1 if currrange is None: currrange = [linenum, linenum] missed_ranges.append(currrange) else: currrange[1] = linenum stmtpos += 1 percent = (len(stmtlines) - len(stmtmissed)) * 100.0 / len(stmtlines) stats.append((filename, percent, len(stmtlines), missed_ranges)) return stats def display_coverage(stats): print "Coverage report:" max_filename_len = max(len(stat[0]) for stat in stats) for filename, percent, total, missed in stats: msg = "%r%s %5.1f%% of %d" % (filename, ' ' * (max_filename_len - len(filename)), percent, total) if len(missed) != 0: for pos in xrange(len(missed)): if missed[pos][0] == missed[pos][1]: missed[pos] = str(missed[pos][0]) elif missed[pos][0] + 1 == missed[pos][1]: missed[pos] = "%d,%d" % tuple(missed[pos]) else: missed[pos] = "%d-%d" % tuple(missed[pos]) msg += "\t Missed: %s" % ','.join(missed) print msg def run(use_coverage=False, use_profiling=False): topdir = canonical_path(os.path.join(os.path.dirname(__file__), '..')) if use_profiling: try: import cProfile as profile except ImportError: import profile modules = profile.run('run_tests(%r, MODNAMES, OTHER_FILES, %r)' % (topdir, use_profiling), os.path.join(topdir, '.runtests.prof')) else: modules = run_tests(topdir, MODNAMES, OTHER_FILES, use_coverage) if use_coverage: display_coverage(get_coverage(topdir, modules, COVERED_LINES)) run() #run(use_profiling=True) xappy-0.5/utils/0000755000175000017500000000000011005556727013501 5ustar richardrichardxappy-0.5/utils/make_xappy_tarballs0000755000175000017500000001371211005462312017437 0ustar richardrichard#!/bin/sh -e # This script is used to generate the tarballs of xapian for xappy. # # These tarballs are based on SVN HEAD, but with the changes from two branches # merged in. Some of the contents of these branches may be merged into HEAD # shortly, but other changes on the branches can't easily be merged to HEAD # during the 1.0.x release series, so will be merged after the 1.0.x series has # been moved into maintenance mode, and HEAD is being used to work towards the # 1.1 series. # # The script depends on various directories being set up, and is probably only # usable on my machine without a fair bit of work first. # The directories used are: # # $basedir/branchpoints/matchspy: a checkout of the matchspy branch at the # revision the branch was made (ie, before any changes were made on it). # # $basedir/branchpoints/opsynonym: a checkout of the opsynonym branch at the # revision the branch was made (ie, before any changes were made on it). # # $basedir/branchpoints/clustering: a checkout of the clustering branch at the # revision the branch was made (ie, before any changes were made on it). # # $basedir/branches/matchspy: a checkout of the matchspy branch at the latest # revision. # # $basedir/branches/opsynonym: a checkout of the opsynonym branch at the # latest revision. # # $basedir/branches/clustering: a checkout of the clustering branch at the # latest revision. # # $basedir/head/trunk: a checkout of HEAD, at the latest revision. # # $xappylibdir: a checkout of xappy/trunk. rev="1.0.6" matchspy_branchpoint="10407" opsynonym_branchpoint="10407" clustering_branchpoint="10407" basedir="$HOME/private/Working/xapian/pristine/" xappylibdir="$HOME/xappy/libs/" echo "Updating branchpoint trees" cd $basedir/branchpoints/matchspy svn update -r$matchspy_branchpoint cd $basedir/branchpoints/opsynonym svn update -r$opsynonym_branchpoint cd $basedir/branchpoints/clustering svn update -r$clustering_branchpoint echo "Updating branch trees" cd $basedir/branches/matchspy svn update cd $basedir/branches/opsynonym svn update cd $basedir/branches/clustering svn update echo "Updating head" cd $basedir/head/trunk svn update head_rev=`svn info | grep Revision | cut -f 2 -d ' '` echo "Exporting clean trees" rm -rf $basedir/branchpoints/matchspy_export svn export $basedir/branchpoints/matchspy $basedir/branchpoints/matchspy_export rm -rf $basedir/branchpoints/opsynonym_export svn export $basedir/branchpoints/opsynonym $basedir/branchpoints/opsynonym_export rm -rf $basedir/branchpoints/clustering_export svn export $basedir/branchpoints/clustering $basedir/branchpoints/clustering_export rm -rf $basedir/branches/matchspy_export svn export $basedir/branches/matchspy $basedir/branches/matchspy_export rm -rf $basedir/branches/opsynonym_export svn export $basedir/branches/opsynonym $basedir/branches/opsynonym_export rm -rf $basedir/branches/clustering_export svn export $basedir/branches/clustering $basedir/branches/clustering_export rm -rf $basedir/head/trunk_export svn export $basedir/head/trunk $basedir/head/trunk_export # Get the diffs we made on branches. echo "Getting patches from matchspy branch" cd $basedir diff -Nur --ignore-matching-lines='\$Author' \ branchpoints/matchspy_export \ branches/matchspy_export \ | filterdiff -x '*/ChangeLog' -x '*/NEWS' -x '*/docs/index.html' \ >$basedir/matchspy_changes.patch echo "Getting patches from opsynonym branch" cd $basedir diff -Nur --ignore-matching-lines='\$Author' \ branchpoints/opsynonym_export \ branches/opsynonym_export \ | filterdiff -x '*/ChangeLog' -x '*/NEWS' -x '*/docs/index.html' \ >$basedir/opsynonym_changes.patch echo "Getting patches from clustering branch" cd $basedir diff -Nur --ignore-matching-lines='\$Author' \ branchpoints/clustering_export \ branches/clustering_export \ | filterdiff -x '*/ChangeLog' -x '*/NEWS' -x '*/docs/index.html' \ >$basedir/clustering_changes.patch # Get the diffs made to HEAD since the branch points echo "Getting changes to HEAD since matchspy branch" cd $basedir diff -Nur --ignore-matching-lines='\$Author' \ branchpoints/matchspy_export \ head/trunk_export \ >$basedir/head_changes_since_matchspy_branch.patch && true echo "Getting changes to HEAD since opsynonym branch" cd $basedir diff -Nur --ignore-matching-lines='\$Author' \ branchpoints/opsynonym_export \ head/trunk_export \ >$basedir/head_changes_since_opsynonym_branch.patch && true echo "Getting changes to HEAD since clustering branch" cd $basedir diff -Nur --ignore-matching-lines='\$Author' \ branchpoints/clustering_export \ head/trunk_export \ >$basedir/head_changes_since_clustering_branch.patch && true # Apply the patches to HEAD echo "Applying patches" cd $basedir/head/trunk_export patch -p2 < $basedir/matchspy_changes.patch patch -p2 < $basedir/opsynonym_changes.patch patch -p2 < $basedir/clustering_changes.patch # Make tarballs echo "Building tarballs" cd $basedir/head/trunk_export ./bootstrap ./configure (cd xapian-core && make && make dist) (cd xapian-bindings && make && make dist) # Copy the tarballs into xappy echo "Repacking tarballs" cd $xappylibdir mkdir -p tmp cd tmp rm -rf xapian-core-* xapian-bindings-* cd $basedir/head/trunk_export cp xapian-core/xapian-core-${rev}.tar.gz $xappylibdir/tmp/ cp xapian-bindings/xapian-bindings-${rev}.tar.gz $xappylibdir/tmp/ cd $xappylibdir/tmp tar zxf $xappylibdir/tmp/xapian-core-${rev}.tar.gz tar zxf $xappylibdir/tmp/xapian-bindings-${rev}.tar.gz mv xapian-core-${rev} xapian-core mv xapian-bindings-${rev} xapian-bindings tar -H ustar -zcf xapian-core-${head_rev}.tgz xapian-core tar -H ustar -zcf xapian-bindings-${head_rev}.tgz xapian-bindings rm -r xapian-core xapian-bindings rm xapian-core-${rev}.tar.gz rm xapian-bindings-${rev}.tar.gz cd $xappylibdir mv tmp/xapian-core-${head_rev}.tgz . mv tmp/xapian-bindings-${head_rev}.tgz . # Make a tarball of the windows build files cd $basedir/head/trunk_export/xapian-maintainer-tools/ tar -H ustar -zcf win32msvc-${head_rev}.tgz win32msvc cp win32msvc-${head_rev}.tgz $xappylibdir/ rmdir tmp xappy-0.5/xappy/0000755000175000017500000000000011005556727013502 5ustar richardrichardxappy-0.5/xappy/__init__.py0000644000175000017500000000246311005445777015622 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Xappy. See the accompanying documentation for details. In particular, there should be an accompanying file "introduction.html" (or "introduction.rst") which gives details of how to use the xappy package. """ __docformat__ = "restructuredtext en" __version__ = '0.5' import _checkxapian from datastructures import Field, UnprocessedDocument, ProcessedDocument from errors import * from fieldactions import FieldActions from indexerconnection import IndexerConnection from searchconnection import SearchConnection from replaylog import set_replay_path xappy-0.5/xappy/_checkxapian.py0000644000175000017500000000314511005456013016457 0ustar richardrichard# Copyright (C) 2008 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""_checkxapian.py: Check the version of xapian used. Raises an ImportError on import if the version used is too old to be used at all. """ __docformat__ = "restructuredtext en" # The minimum version of xapian required to work at all. min_xapian_version = (1, 0, 6) # Dictionary of features we can't support do to them being missing from the # available version of xapian. missing_features = {} import xapian versions = xapian.major_version(), xapian.minor_version(), xapian.revision() if versions < min_xapian_version: raise ImportError(""" Xapian Python bindings installed, but need at least version %d.%d.%d - got %s """.strip() % tuple(list(min_xapian_version) + [xapian.version_string()])) if not hasattr(xapian, 'TermCountMatchSpy'): missing_features['tags'] = 1 if not hasattr(xapian, 'CategorySelectMatchSpy'): missing_features['facets'] = 1 xappy-0.5/xappy/datastructures.py0000644000175000017500000002145210772400231017121 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""datastructures.py: Datastructures for search engine core. """ __docformat__ = "restructuredtext en" import errors from replaylog import log import xapian import cPickle class Field(object): # Use __slots__ because we're going to have very many Field objects in # typical usage. __slots__ = 'name', 'value' def __init__(self, name, value): self.name = name self.value = value def __repr__(self): return 'Field(%r, %r)' % (self.name, self.value) class UnprocessedDocument(object): """A unprocessed document to be passed to the indexer. This represents an item to be processed and stored in the search engine. Each document will be processed by the indexer to generate a ProcessedDocument, which can then be stored in the search engine index. Note that some information in an UnprocessedDocument will not be represented in the ProcessedDocument: therefore, it is not possible to retrieve an UnprocessedDocument from the search engine index. An unprocessed document is a simple container with two attributes: - `fields` is a list of Field objects, or an iterator returning Field objects. - `id` is a string holding a unique identifier for the document (or None to get the database to allocate a unique identifier automatically when the document is added). """ __slots__ = 'id', 'fields', def __init__(self, id=None, fields=None): self.id = id if fields is None: self.fields = [] else: self.fields = fields def __repr__(self): return 'UnprocessedDocument(%r, %r)' % (self.id, self.fields) class ProcessedDocument(object): """A processed document, as stored in the index. This represents an item which is ready to be stored in the search engine, or which has been returned by the search engine. """ __slots__ = '_doc', '_fieldmappings', '_data', def __init__(self, fieldmappings, xapdoc=None): """Create a ProcessedDocument. `fieldmappings` is the configuration from a database connection used lookup the configuration to use to store each field. If supplied, `xapdoc` is a Xapian document to store in the processed document. Otherwise, a new Xapian document is created. """ if xapdoc is None: self._doc = log(xapian.Document) else: self._doc = xapdoc self._fieldmappings = fieldmappings self._data = None def add_term(self, field, term, wdfinc=1, positions=None): """Add a term to the document. Terms are the main unit of information used for performing searches. - `field` is the field to add the term to. - `term` is the term to add. - `wdfinc` is the value to increase the within-document-frequency measure for the term by. - `positions` is the positional information to add for the term. This may be None to indicate that there is no positional information, or may be an integer to specify one position, or may be a sequence of integers to specify several positions. (Note that the wdf is not increased automatically for each position: if you add a term at 7 positions, and the wdfinc value is 2, the total wdf for the term will only be increased by 2, not by 14.) """ prefix = self._fieldmappings.get_prefix(field) if len(term) > 0: # We use the following check, rather than "isupper()" to ensure # that we match the check performed by the queryparser, regardless # of our locale. if ord(term[0]) >= ord('A') and ord(term[0]) <= ord('Z'): prefix = prefix + ':' # Note - xapian currently restricts term lengths to about 248 # characters - except that zero bytes are encoded in two bytes, so # in practice a term of length 125 characters could be too long. # Xapian will give an error when commit() is called after such # documents have been added to the database. # As a simple workaround, we give an error here for terms over 220 # characters, which will catch most occurrences of the error early. # # In future, it might be good to change to a hashing scheme in this # situation (or for terms over, say, 64 characters), where the # characters after position 64 are hashed (we obviously need to do this # hashing at search time, too). if len(prefix + term) > 220: raise errors.IndexerError("Field %r is too long: maximum length " "220 - was %d (%r)" % (field, len(prefix + term), prefix + term)) if positions is None: self._doc.add_term(prefix + term, wdfinc) elif isinstance(positions, int): self._doc.add_posting(prefix + term, positions, wdfinc) else: self._doc.add_term(prefix + term, wdfinc) for pos in positions: self._doc.add_posting(prefix + term, pos, 0) def add_value(self, field, value, purpose=''): """Add a value to the document. Values are additional units of information used when performing searches. Note that values are _not_ intended to be used to store information for display in the search results - use the document data for that. The intention is that as little information as possible is stored in values, so that they can be accessed as quickly as possible during the search operation. Unlike terms, each document may have at most one value in each field (whereas there may be an arbitrary number of terms in a given field). If an attempt to add multiple values to a single field is made, only the last value added will be stored. """ slot = self._fieldmappings.get_slot(field, purpose) self._doc.add_value(slot, value) def get_value(self, field, purpose=''): """Get a value from the document. """ slot = self._fieldmappings.get_slot(field, purpose) return self._doc.get_value(slot) def prepare(self): """Prepare the document for adding to a xapian database. This updates the internal xapian document with any changes which have been made, and then returns it. """ if self._data is not None: self._doc.set_data(cPickle.dumps(self._data, 2)) self._data = None return self._doc def _get_data(self): if self._data is None: rawdata = self._doc.get_data() if rawdata == '': self._data = {} else: self._data = cPickle.loads(rawdata) return self._data def _set_data(self, data): if not isinstance(data, dict): raise TypeError("Cannot set data to any type other than a dict") self._data = data data = property(_get_data, _set_data, doc= """The data stored in this processed document. This data is a dictionary of entries, where the key is a fieldname, and the value is a list of strings. """) def _get_id(self): tl = self._doc.termlist() try: term = tl.skip_to('Q').term if len(term) == 0 or term[0] != 'Q': return None except StopIteration: return None return term[1:] def _set_id(self, id): tl = self._doc.termlist() try: term = tl.skip_to('Q').term except StopIteration: term = '' if len(term) != 0 and term[0] == 'Q': self._doc.remove_term(term) if id is not None: self._doc.add_term('Q' + id, 0) id = property(_get_id, _set_id, doc= """The unique ID for this document. """) def __repr__(self): return '' % (self.id) if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/xappy/datastructures_doctest1.txt0000644000175000017500000000147310667526666021147 0ustar richardrichard >>> from fieldmappings import FieldMappings >>> maps = FieldMappings() Make a processed document. >>> doc = ProcessedDocument(maps) >>> print doc.id None >>> doc.id = '1' >>> print doc.id 1 >>> doc.id = '_' >>> print doc.id _ >>> print repr(doc.data) {} >>> doc.data['foo'] = ['1', '2'] >>> print repr(doc.data) {'foo': ['1', '2']} Adding terms which are too long gives an error straight-away. >>> maps.add_prefix('foo') >>> doc.add_term('foo', 'a' * 250) Traceback (most recent call last): ... IndexerError: Field 'foo' is too long: maximum length 220 - was 252 ('XAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') xappy-0.5/xappy/errors.py0000644000175000017500000000573210700703107015362 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""errors.py: Exceptions for the search engine core. """ __docformat__ = "restructuredtext en" class SearchEngineError(Exception): r"""Base class for exceptions thrown by the search engine. Any errors generated by xappy itself, or by xapian, will be instances of this class or its subclasses. """ class IndexerError(SearchEngineError): r"""Class used to report errors relating to the indexing API. """ class SearchError(SearchEngineError): r"""Class used to report errors relating to the search API. """ class XapianError(SearchEngineError): r"""Base class for exceptions thrown by the xapian. Any errors generated by xapian will be instances of this class or its subclasses. """ def _rebase_xapian_exceptions(): """Add new base classes for all the xapian exceptions. """ import xapian for name in ( 'AssertionError', 'DatabaseCorruptError', 'DatabaseCreateError', 'DatabaseError', 'DatabaseLockError', 'DatabaseModifiedError', 'DatabaseOpeningError', 'DatabaseVersionError', 'DocNotFoundError', # We skip 'Error' because it inherits directly from exception # and this causes problems with method resolution order. # However, we probably don't need it anyway, because it's # just a base class, and shouldn't ever actually be raised. # Users can catch xappy.XapianError instead. 'FeatureUnavailableError', 'InternalError', 'InvalidArgumentError', 'InvalidOperationError', 'LogicError', 'NetworkError', 'NetworkTimeoutError', 'QueryParserError', 'RangeError', 'RuntimeError', 'UnimplementedError', ): xapian_exception = getattr(xapian, name, None) if xapian_exception is not None: xapian_exception.__bases__ += (XapianError, ) globals()['Xapian' + name] = xapian_exception _rebase_xapian_exceptions() xappy-0.5/xappy/errors_doctest1.txt0000644000175000017500000000175010700703214017352 0ustar richardrichardXappy exports all the xapian errors as "XapianFooError", corresponding to xapian.FooError. Firstly, we need to test that we can catch one of these errors. Lets play with DatabaseLockError because it's easy to generate. >>> import xappy >>> db1 = xappy.IndexerConnection('foo') >>> try: ... db2 = xappy.IndexerConnection('foo') ... except xappy.XapianDatabaseLockError: ... print "Got XapianDatabaseLockError" Got XapianDatabaseLockError Xappy also modifies all the Xapian errors so that they inherit from xappy.XapianError, so we can catch all Xapian errors this way: >>> try: ... db2 = xappy.IndexerConnection('foo') ... except xappy.XapianError: ... print "Got XapianError" Got XapianError xappy.XapianError is a subclass of xappy.SearchEngineError, so all errors from xappy can be caught using xappy.SearchEngineError: >>> try: ... db2 = xappy.IndexerConnection('foo') ... except xappy.SearchEngineError: ... print "Got SearchEngineError" Got SearchEngineError xappy-0.5/xappy/fieldactions.py0000644000175000017500000004145111005455561016517 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""fieldactions.py: Definitions and implementations of field actions. """ __docformat__ = "restructuredtext en" import _checkxapian import errors import marshall from replaylog import log import xapian import parsedate def _act_store_content(fieldname, doc, value, context): """Perform the STORE_CONTENT action. """ try: fielddata = doc.data[fieldname] except KeyError: fielddata = [] doc.data[fieldname] = fielddata fielddata.append(value) def _act_index_exact(fieldname, doc, value, context): """Perform the INDEX_EXACT action. """ doc.add_term(fieldname, value, 0) def _act_tag(fieldname, doc, value, context): """Perform the TAG action. """ doc.add_term(fieldname, value.lower(), 0) def _act_facet(fieldname, doc, value, context, type=None): """Perform the FACET action. """ if type is None or type == 'string': value = value.lower() doc.add_term(fieldname, value, 0) serialiser = log(xapian.StringListSerialiser, doc.get_value(fieldname, 'facet')) serialiser.append(value) doc.add_value(fieldname, serialiser.get(), 'facet') else: marshaller = SortableMarshaller() fn = marshaller.get_marshall_function(fieldname, type) doc.add_value(fieldname, fn(fieldname, value), 'facet') def _act_index_freetext(fieldname, doc, value, context, weight=1, language=None, stop=None, spell=False, nopos=False, allow_field_specific=True, search_by_default=True): """Perform the INDEX_FREETEXT action. """ termgen = log(xapian.TermGenerator) if language is not None: termgen.set_stemmer(log(xapian.Stem, language)) if stop is not None: stopper = log(xapian.SimpleStopper) for term in stop: stopper.add (term) termgen.set_stopper (stopper) if spell: termgen.set_database(context.index) termgen.set_flags(termgen.FLAG_SPELLING) termgen.set_document(doc._doc) if search_by_default: termgen.set_termpos(context.current_position) # Store a copy of the field without a prefix, for non-field-specific # searches. if nopos: termgen.index_text_without_positions(value, weight, '') else: termgen.index_text(value, weight, '') if allow_field_specific: # Store a second copy of the term with a prefix, for field-specific # searches. prefix = doc._fieldmappings.get_prefix(fieldname) if len(prefix) != 0: termgen.set_termpos(context.current_position) if nopos: termgen.index_text_without_positions(value, weight, prefix) else: termgen.index_text(value, weight, prefix) # Add a gap between each field instance, so that phrase searches don't # match across instances. termgen.increase_termpos(10) context.current_position = termgen.get_termpos() class SortableMarshaller(object): """Implementation of marshalling for sortable values. """ def __init__(self, indexing=True): if indexing: self._err = errors.IndexerError else: self._err = errors.SearchError def marshall_string(self, fieldname, value): """Marshall a value for sorting in lexicograpical order. This returns the input as the output, since strings already sort in lexicographical order. """ return value def marshall_float(self, fieldname, value): """Marshall a value for sorting as a floating point value. """ # convert the value to a float try: value = float(value) except ValueError: raise self._err("Value supplied to field %r must be a " "valid floating point number: was %r" % (fieldname, value)) return marshall.float_to_string(value) def marshall_date(self, fieldname, value): """Marshall a value for sorting as a date. """ try: value = parsedate.date_from_string(value) except ValueError, e: raise self._err("Value supplied to field %r must be a " "valid date: was %r: error is '%s'" % (fieldname, value, str(e))) return marshall.date_to_string(value) def get_marshall_function(self, fieldname, sorttype): """Get a function used to marshall values of a given sorttype. """ try: return { None: self.marshall_string, 'string': self.marshall_string, 'float': self.marshall_float, 'date': self.marshall_date, }[sorttype] except KeyError: raise self._err("Unknown sort type %r for field %r" % (sorttype, fieldname)) def _act_sort_and_collapse(fieldname, doc, value, context, type=None): """Perform the SORTABLE action. """ marshaller = SortableMarshaller() fn = marshaller.get_marshall_function(fieldname, type) value = fn(fieldname, value) doc.add_value(fieldname, value, 'collsort') class ActionContext(object): """The context in which an action is performed. This is just used to pass term generators, word positions, and the like around. """ def __init__(self, index): self.current_language = None self.current_position = 0 self.index = index class FieldActions(object): """An object describing the actions to be performed on a field. The supported actions are: - `STORE_CONTENT`: store the unprocessed content of the field in the search engine database. All fields which need to be displayed or used when displaying the search results need to be given this action. - `INDEX_EXACT`: index the exact content of the field as a single search term. Fields whose contents need to be searchable as an "exact match" need to be given this action. - `INDEX_FREETEXT`: index the content of this field as text. The content will be split into terms, allowing free text searching of the field. Four optional parameters may be supplied: - 'weight' is a multiplier to apply to the importance of the field. This must be an integer, and the default value is 1. - 'language' is the language to use when processing the field. This can be expressed as an ISO 2-letter language code. The supported languages are those supported by the xapian core in use. - 'stop' is an iterable of stopwords to filter out of the generated terms. Note that due to Xapian design, only non-positional terms are affected, so this is of limited use. - 'spell' is a boolean flag - if true, the contents of the field will be used for spelling correction. - 'nopos' is a boolean flag - if true, positional information is not stored. - 'allow_field_specific' is a boolean flag - if False, prevents terms with the field prefix being generated. This means that searches specific to this field will not work, and thus should only be used when only non-field specific searches are desired. Defaults to True. - 'search_by_default' is a boolean flag - if False, the field will not be searched by non-field specific searches. If True, or omitted, the field will be included in searches for non field-specific searches. - `SORTABLE`: index the content of the field such that it can be used to sort result sets. It also allows result sets to be restricted to those documents with a field values in a given range. One optional parameter may be supplied: - 'type' is a value indicating how to sort the field. It has several possible values: - 'string' - sort in lexicographic (ie, alphabetical) order. This is the default, used if no type is set. - 'float' - treat the values as (decimal representations of) floating point numbers, and sort in numerical order. The values in the field must be valid floating point numbers (according to Python's float() function). - 'date' - sort in date order. The values must be valid dates (either Python datetime.date objects, or ISO 8601 format (ie, YYYYMMDD or YYYY-MM-DD). - `COLLAPSE`: index the content of the field such that it can be used to "collapse" result sets, such that only the highest result with each value of the field will be returned. - `TAG`: the field contains tags; these are strings, which will be matched in a case insensitive way, but otherwise must be exact matches. Tag fields can be searched for by making an explict query (ie, using query_field(), but not with query_parse()). A list of the most frequent tags in a result set can also be accessed easily. - `FACET`: the field represents a classification facet; these are strings which will be matched exactly, but a list of all the facets present in the result set can also be accessed easily - in addition, a suitable subset of the facets, and a selection of the facet values, present in the result set can be calculated. One optional parameter may be supplied: - 'type' is a value indicating the type of facet contained in the field: - 'string' - the facet values are exact binary strings. - 'float' - the facet values are floating point numbers. """ # See the class docstring for the meanings of the following constants. STORE_CONTENT = 1 INDEX_EXACT = 2 INDEX_FREETEXT = 3 SORTABLE = 4 COLLAPSE = 5 TAG = 6 FACET = 7 # Sorting and collapsing store the data in a value, but the format depends # on the sort type. Easiest way to implement is to treat them as the same # action. SORT_AND_COLLAPSE = -1 _unsupported_actions = [] if 'tags' in _checkxapian.missing_features: _unsupported_actions.append(TAG) if 'facets' in _checkxapian.missing_features: _unsupported_actions.append(FACET) def __init__(self, fieldname): # Dictionary of actions, keyed by type. self._actions = {} self._fieldname = fieldname def add(self, field_mappings, action, **kwargs): """Add an action to perform on a field. """ if action in self._unsupported_actions: raise errors.IndexerError("Action unsupported with this release of xapian") if action not in (FieldActions.STORE_CONTENT, FieldActions.INDEX_EXACT, FieldActions.INDEX_FREETEXT, FieldActions.SORTABLE, FieldActions.COLLAPSE, FieldActions.TAG, FieldActions.FACET, ): raise errors.IndexerError("Unknown field action: %r" % action) info = self._action_info[action] # Check parameter names for key in kwargs.keys(): if key not in info[1]: raise errors.IndexerError("Unknown parameter name for action %r: %r" % (info[0], key)) # Fields cannot be indexed both with "EXACT" and "FREETEXT": whilst we # could implement this, the query parser wouldn't know what to do with # searches. if action == FieldActions.INDEX_EXACT: if FieldActions.INDEX_FREETEXT in self._actions: raise errors.IndexerError("Field %r is already marked for indexing " "as free text: cannot mark for indexing " "as exact text as well" % self._fieldname) if action == FieldActions.INDEX_FREETEXT: if FieldActions.INDEX_EXACT in self._actions: raise errors.IndexerError("Field %r is already marked for indexing " "as exact text: cannot mark for indexing " "as free text as well" % self._fieldname) # Fields cannot be indexed as more than one type for "SORTABLE": to # implement this, we'd need to use a different prefix for each sortable # type, but even then the search end wouldn't know what to sort on when # searching. Also, if they're indexed as "COLLAPSE", the value must be # stored in the right format for the type "SORTABLE". if action == FieldActions.SORTABLE or action == FieldActions.COLLAPSE: if action == FieldActions.COLLAPSE: sorttype = None else: try: sorttype = kwargs['type'] except KeyError: sorttype = 'string' kwargs['type'] = sorttype action = FieldActions.SORT_AND_COLLAPSE try: oldsortactions = self._actions[FieldActions.SORT_AND_COLLAPSE] except KeyError: oldsortactions = () if len(oldsortactions) > 0: for oldsortaction in oldsortactions: oldsorttype = oldsortaction['type'] if sorttype == oldsorttype or oldsorttype is None: # Use new type self._actions[action] = [] elif sorttype is None: # Use old type return else: raise errors.IndexerError("Field %r is already marked for " "sorting, with a different " "sort type" % self._fieldname) if 'prefix' in info[3]: field_mappings.add_prefix(self._fieldname) if 'slot' in info[3]: purposes = info[3]['slot'] if isinstance(purposes, basestring): field_mappings.add_slot(self._fieldname, purposes) else: slotnum = None for purpose in purposes: slotnum = field_mappings.get_slot(self._fieldname, purpose) if slotnum is not None: break for purpose in purposes: field_mappings.add_slot(self._fieldname, purpose, slotnum=slotnum) # Make an entry for the action if action not in self._actions: self._actions[action] = [] # Check for repetitions of actions for old_action in self._actions[action]: if old_action == kwargs: return # Append the action to the list of actions self._actions[action].append(kwargs) def perform(self, doc, value, context): """Perform the actions on the field. - `doc` is a ProcessedDocument to store the result of the actions in. - `value` is a string holding the value of the field. - `context` is an ActionContext object used to keep state in. """ for type, actionlist in self._actions.iteritems(): info = self._action_info[type] for kwargs in actionlist: info[2](self._fieldname, doc, value, context, **kwargs) _action_info = { STORE_CONTENT: ('STORE_CONTENT', (), _act_store_content, {}, ), INDEX_EXACT: ('INDEX_EXACT', (), _act_index_exact, {'prefix': True}, ), INDEX_FREETEXT: ('INDEX_FREETEXT', ('weight', 'language', 'stop', 'spell', 'nopos', 'allow_field_specific', 'search_by_default', ), _act_index_freetext, {'prefix': True, }, ), SORTABLE: ('SORTABLE', ('type', ), None, {'slot': 'collsort',}, ), COLLAPSE: ('COLLAPSE', (), None, {'slot': 'collsort',}, ), TAG: ('TAG', (), _act_tag, {'prefix': True,}, ), FACET: ('FACET', ('type', ), _act_facet, {'prefix': True, 'slot': 'facet',}, ), SORT_AND_COLLAPSE: ('SORT_AND_COLLAPSE', ('type', ), _act_sort_and_collapse, {'slot': 'collsort',}, ), } if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/xappy/fieldmappings.py0000644000175000017500000001262410667526666016717 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""fieldmappings.py: Mappings from field names to term prefixes, etc. """ __docformat__ = "restructuredtext en" import cPickle as _cPickle class FieldMappings(object): """Mappings from field names to term prefixes, slot values, etc. The following mappings are maintained: - a mapping from field name to the string prefix to insert at the start of terms. - a mapping from field name to the slot numbers to store the field contents in. """ __slots__ = '_prefixes', '_prefixcount', '_slots', '_slotcount', def __init__(self, serialised=None): """Create a new field mapping object, or unserialise a saved one. """ if serialised is not None: (self._prefixes, self._prefixcount, self._slots, self._slotcount) = _cPickle.loads(serialised) else: self._prefixes = {} self._prefixcount = 0 self._slots = {} self._slotcount = 0 def _genPrefix(self): """Generate a previously unused prefix. Prefixes are uppercase letters, and start with 'X' (this is a Xapian convention, for compatibility with other Xapian tools: other starting letters are reserved for special meanings): >>> maps = FieldMappings() >>> maps._genPrefix() 'XA' >>> maps._genPrefix() 'XB' >>> [maps._genPrefix() for i in xrange(60)] ['XC', 'XD', 'XE', 'XF', 'XG', 'XH', 'XI', 'XJ', 'XK', 'XL', 'XM', 'XN', 'XO', 'XP', 'XQ', 'XR', 'XS', 'XT', 'XU', 'XV', 'XW', 'XX', 'XY', 'XZ', 'XAA', 'XBA', 'XCA', 'XDA', 'XEA', 'XFA', 'XGA', 'XHA', 'XIA', 'XJA', 'XKA', 'XLA', 'XMA', 'XNA', 'XOA', 'XPA', 'XQA', 'XRA', 'XSA', 'XTA', 'XUA', 'XVA', 'XWA', 'XXA', 'XYA', 'XZA', 'XAB', 'XBB', 'XCB', 'XDB', 'XEB', 'XFB', 'XGB', 'XHB', 'XIB', 'XJB'] >>> maps = FieldMappings() >>> [maps._genPrefix() for i in xrange(27*26 + 5)][-10:] ['XVZ', 'XWZ', 'XXZ', 'XYZ', 'XZZ', 'XAAA', 'XBAA', 'XCAA', 'XDAA', 'XEAA'] """ res = [] self._prefixcount += 1 num = self._prefixcount while num != 0: ch = (num - 1) % 26 res.append(chr(ch + ord('A'))) num -= ch num = num // 26 return 'X' + ''.join(res) def get_fieldname_from_prefix(self, prefix): """Get a fieldname from a prefix. If the prefix is not found, return None. """ for key, val in self._prefixes.iteritems(): if val == prefix: return key return None def get_prefix(self, fieldname): """Get the prefix used for a given field name. """ return self._prefixes[fieldname] def get_slot(self, fieldname, purpose): """Get the slot number used for a given field name and purpose. """ return self._slots[(fieldname, purpose)] def add_prefix(self, fieldname): """Allocate a prefix for the given field. If a prefix is already allocated for this field, this has no effect. """ if fieldname in self._prefixes: return self._prefixes[fieldname] = self._genPrefix() def add_slot(self, fieldname, purpose, slotnum=None): """Allocate a slot number for the given field and purpose. If a slot number is already allocated for this field and purpose, this has no effect. Returns the slot number allocated for the field and purpose (whether newly allocated, or previously allocated). If `slotnum` is supplied, the number contained in it is used to allocate the new slot, instead of allocating a new number. No checks will be made to ensure that the slot number doesn't collide with existing (or later allocated) numbers: the main purpose of this parameter is to share allocations - ie, to collide deliberately. """ try: return self._slots[(fieldname, purpose)] except KeyError: pass if slotnum is None: self._slots[(fieldname, purpose)] = self._slotcount self._slotcount += 1 return self._slotcount - 1 else: self._slots[(fieldname, purpose)] = slotnum return slotnum def serialise(self): """Serialise the field mappings to a string. This can be unserialised by passing the result of this method to the constructor of a new FieldMappings object. """ return _cPickle.dumps((self._prefixes, self._prefixcount, self._slots, self._slotcount, ), 2) xappy-0.5/xappy/fieldmappings_doctest1.txt0000644000175000017500000000027310653377546020705 0ustar richardrichard Test basic workings of the FieldMappings. >>> maps = FieldMappings() >>> maps.get_fieldname_from_prefix('XA') >>> maps.add_prefix('foo') >>> maps.get_fieldname_from_prefix('XA') 'foo' xappy-0.5/xappy/highlight.py0000644000175000017500000002410510725764413016026 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""highlight.py: Highlight and summarise text. """ __docformat__ = "restructuredtext en" import re import xapian class Highlighter(object): """Class for highlighting text and creating contextual summaries. >>> hl = Highlighter("en") >>> hl.makeSample('Hello world.', ['world']) 'Hello world.' >>> hl.highlight('Hello world', ['world'], ('<', '>')) 'Hello ' """ # split string into words, spaces, punctuation and markup tags _split_re = re.compile(r'<\w+[^>]*>||[\w\']+|\s+|[^\w\'\s<>/]+') def __init__(self, language_code='en', stemmer=None): """Create a new highlighter for the specified language. """ if stemmer is not None: self.stem = stemmer else: self.stem = xapian.Stem(language_code) def _split_text(self, text, strip_tags=False): """Split some text into words and non-words. - `text` is the text to process. It may be a unicode object or a utf-8 encoded simple string. - `strip_tags` is a flag - False to keep tags, True to strip all tags from the output. Returns a list of utf-8 encoded simple strings. """ if isinstance(text, unicode): text = text.encode('utf-8') words = self._split_re.findall(text) if strip_tags: return [w for w in words if w[0] != '<'] else: return words def _strip_prefix(self, term): """Strip the prefix off a term. Prefixes are any initial capital letters, with the exception that R always ends a prefix, even if followed by capital letters. >>> hl = Highlighter("en") >>> print hl._strip_prefix('hello') hello >>> print hl._strip_prefix('Rhello') hello >>> print hl._strip_prefix('XARHello') Hello >>> print hl._strip_prefix('XAhello') hello >>> print hl._strip_prefix('XAh') h >>> print hl._strip_prefix('XA') """ for p in xrange(len(term)): if term[p].islower(): return term[p:] elif term[p] == 'R': return term[p+1:] return '' def _query_to_stemmed_words(self, query): """Convert a query to a list of stemmed words. - `query` is the query to parse: it may be xapian.Query object, or a sequence of terms. """ if isinstance(query, xapian.Query): return [self._strip_prefix(t) for t in query] else: return [self.stem(q.lower()) for q in query] def makeSample(self, text, query, maxlen=600, hl=None): """Make a contextual summary from the supplied text. This basically works by splitting the text into phrases, counting the query terms in each, and keeping those with the most. Any markup tags in the text will be stripped. `text` is the source text to summarise. `query` is either a Xapian query object or a list of (unstemmed) term strings. `maxlen` is the maximum length of the generated summary. `hl` is a pair of strings to insert around highlighted terms, e.g. ('', '') """ # coerce maxlen into an int, otherwise truncation doesn't happen maxlen = int(maxlen) words = self._split_text(text, True) terms = self._query_to_stemmed_words(query) # build blocks delimited by puncuation, and count matching words in each block # blocks[n] is a block [firstword, endword, charcount, termcount, selected] blocks = [] start = end = count = blockchars = 0 while end < len(words): blockchars += len(words[end]) if words[end].isalnum(): if self.stem(words[end].lower()) in terms: count += 1 end += 1 elif words[end] in ',.;:?!\n': end += 1 blocks.append([start, end, blockchars, count, False]) start = end blockchars = 0 count = 0 else: end += 1 if start != end: blocks.append([start, end, blockchars, count, False]) if len(blocks) == 0: return '' # select high-scoring blocks first, down to zero-scoring chars = 0 for count in xrange(3, -1, -1): for b in blocks: if b[3] >= count: b[4] = True chars += b[2] if chars >= maxlen: break if chars >= maxlen: break # assemble summary words2 = [] lastblock = -1 for i, b in enumerate(blocks): if b[4]: if i != lastblock + 1: words2.append('..') words2.extend(words[b[0]:b[1]]) lastblock = i if not blocks[-1][4]: words2.append('..') # trim down to maxlen l = 0 for i in xrange (len (words2)): l += len (words2[i]) if l >= maxlen: words2[i:] = ['..'] break if hl is None: return ''.join(words2) else: return self._hl(words2, terms, hl) def highlight(self, text, query, hl, strip_tags=False): """Add highlights (string prefix/postfix) to a string. `text` is the source to highlight. `query` is either a Xapian query object or a list of (unstemmed) term strings. `hl` is a pair of highlight strings, e.g. ('', '') `strip_tags` strips HTML markout iff True >>> hl = Highlighter() >>> qp = xapian.QueryParser() >>> q = qp.parse_query('cat dog') >>> tags = ('[[', ']]') >>> hl.highlight('The cat went Dogging; but was dog tired.', q, tags) 'The [[cat]] went [[Dogging]]; but was [[dog]] tired.' """ words = self._split_text(text, strip_tags) terms = self._query_to_stemmed_words(query) return self._hl(words, terms, hl) def _hl(self, words, terms, hl): """Add highlights to a list of words. `words` is the list of words and non-words to be highlighted.. `terms` is the list of stemmed words to look for. """ for i, w in enumerate(words): # HACK - more forgiving about stemmed terms wl = w.lower() if wl in terms or self.stem (wl) in terms: words[i] = ''.join((hl[0], w, hl[1])) return ''.join(words) __test__ = { 'no_punc': r''' Test the highlighter's behaviour when there is no punctuation in the sample text (regression test - used to return no output): >>> hl = Highlighter("en") >>> hl.makeSample('Hello world', ['world']) 'Hello world' ''', 'stem_levels': r''' Test highlighting of words, and how it works with stemming: >>> hl = Highlighter("en") # "word" and "wording" stem to "word", so the following 4 calls all return # the same thing >>> hl.makeSample('Hello. word. wording. wordinging.', ['word'], hl='<>') 'Hello. . . wordinging.' >>> hl.highlight('Hello. word. wording. wordinging.', ['word'], '<>') 'Hello. . . wordinging.' >>> hl.makeSample('Hello. word. wording. wordinging.', ['wording'], hl='<>') 'Hello. . . wordinging.' >>> hl.highlight('Hello. word. wording. wordinging.', ['wording'], '<>') 'Hello. . . wordinging.' # "wordinging" stems to "wording", so only the last two words are # highlighted for this one. >>> hl.makeSample('Hello. word. wording. wordinging.', ['wordinging'], hl='<>') 'Hello. word. . .' >>> hl.highlight('Hello. word. wording. wordinging.', ['wordinging'], '<>') 'Hello. word. . .' ''', 'supplied_stemmer': r''' Test behaviour if we pass in our own stemmer: >>> stem = xapian.Stem('en') >>> hl = Highlighter(stemmer=stem) >>> hl.highlight('Hello. word. wording. wordinging.', ['word'], '<>') 'Hello. . . wordinging.' ''', 'unicode': r''' Test behaviour if we pass in unicode input: >>> hl = Highlighter('en') >>> hl.highlight(u'Hello\xf3. word. wording. wordinging.', ['word'], '<>') 'Hello\xc3\xb3. . . wordinging.' ''', 'no_sample': r''' Test behaviour if we pass in unicode input: >>> hl = Highlighter('en') >>> hl.makeSample(u'', ['word']) '' ''', 'short_samples': r''' >>> hl = Highlighter('en') >>> hl.makeSample("A boring start. Hello world indeed. A boring end.", ['hello'], 20, ('<', '>')) '.. world ..' >>> hl.makeSample("A boring start. Hello world indeed. A boring end.", ['hello'], 40, ('<', '>')) 'A boring start. world indeed...' >>> hl.makeSample("A boring start. Hello world indeed. A boring end.", ['boring'], 40, ('<', '>')) 'A start... A end.' ''', 'apostrophes': r''' >>> hl = Highlighter('en') >>> hl.makeSample("A boring start. Hello world's indeed. A boring end.", ['world'], 40, ('<', '>')) "A boring start. Hello indeed..." ''', } if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/xappy/highlight_doctest1.txt0000644000175000017500000002124610725765213020025 0ustar richardrichard>>> teststr = r''''Python Tutorial Previous: 9. Classes Up: Python Tutorial Next: 11. Brief Tour of Subsections 10.1 Operating System Interface 10.2 File Wildcards 10.3 Command Line Arguments 10.4 Error Output Redirection and Program Termination 10.5 String Pattern Matching 10.6 Mathematics 10.7 Internet Access 10.8 Dates and Times 10.9 Data Compression 10.10 Performance Measurement 10.11 Quality Control 10.12 Batteries Included 10. Brief Tour of the Standard Library 10.1 Operating System Interface The os module provides dozens of functions for interacting with the operating system: >>> import os >>> os.system(\'time 0:02\') 0 >>> os.getcwd() # Return the current working directory \'C:\\\\Python25\' >>> os.chdir(\'/server/accesslogs\') Be sure to use the "import os" style instead of "from os import *". This will keep os.open() from shadowing the builtin open() function which operates much differently. The builtin dir() and help() functions are useful as interactive aids for working with large modules like os: >>> import os >>> dir(os) >>> help(os) For daily file and directory management tasks, the shutil module provides a higher level interface that is easier to use: >>> import shutil >>> shutil.copyfile(\'data.db\', \'archive.db\') >>> shutil.move(\'/build/executables\', \'installdir\') 10.2 File Wildcards The glob module provides a function for making file lists from directory wildcard searches: >>> import glob >>> glob.glob(\'*.py\') [\'primes.py\', \'random.py\', \'quote.py\'] 10.3 Command Line Arguments Common utility scripts often need to process command line arguments. These arguments are stored in the sys module\'s argv attribute as a list. For instance the following output results from running "python demo.py one two three" at the command line: >>> import sys >>> print sys.argv [\'demo.py\', \'one\', \'two\', \'three\'] The getopt module processes sys.argv using the conventions of the Unix getopt() function. More powerful and flexible command line processing is provided by the optparse module. 10.4 Error Output Redirection and Program Termination The sys module also has attributes for stdin, stdout, and stderr. The latter is useful for emitting warnings and error messages to make them visible even when stdout has been redirected: >>> sys.stderr.write(\'Warning, log file not found starting a new one\\n\') Warning, log file not found starting a new one The most direct way to terminate a script is to use "sys.exit()". 10.5 String Pattern Matching The re module provides regular expression tools for advanced string processing. For complex matching and manipulation, regular expressions offer succinct, optimized solutions: >>> import re >>> re.findall(r\'\\bf[a-z]*\', \'which foot or hand fell fastest\') [\'foot\', \'fell\', \'fastest\'] >>> re.sub(r\'(\\b[a-z]+) \\1\', r\'\\1\', \'cat in the the hat\') \'cat in the hat\' When only simple capabilities are needed, string methods are preferred because they are easier to read and debug: >>> \'tea for too\'.replace(\'too\', \'two\') \'tea for two\' 10.6 Mathematics The math module gives access to the underlying C library functions for floating point math: >>> import math >>> math.cos(math.pi / 4.0) 0.70710678118654757 >>> math.log(1024, 2) 10.0 The random module provides tools for making random selections: >>> import random >>> random.choice([\'apple\', \'pear\', \'banana\']) \'apple\' >>> random.sample(xrange(100), 10) # sampling without replacement [30, 83, 16, 4, 8, 81, 41, 50, 18, 33] >>> random.random() # random float 0.17970987693706186 >>> random.randrange(6) # random integer chosen from range(6) 4 10.7 Internet Access There are a number of modules for accessing the internet and processing internet protocols. Two of the simplest are urllib2 for retrieving data from urls and smtplib for sending mail: >>> import urllib2 >>> for line in urllib2.urlopen(\'http://tycho.usno.navy.mil/cgi-bin/timer.pl\'): ... if \'EST\' in line or \'EDT\' in line: # look for Eastern Time ... print line
Nov. 25, 09:43:32 PM EST >>> import smtplib >>> server = smtplib.SMTP(\'localhost\') >>> server.sendmail(\'soothsayer@example.org\', \'jcaesar@example.org\', """To: jcaesar@example.org From: soothsayer@example.org Beware the Ides of March. """) >>> server.quit() 10.8 Dates and Times The datetime module supplies classes for manipulating dates and times in both simple and complex ways. While date and time arithmetic is supported, the focus of the implementation is on efficient member extraction for output formatting and manipulation. The module also supports objects that are timezone aware. # dates are easily constructed and formatted >>> from datetime import date >>> now = date.today() >>> now datetime.date(2003, 12, 2) >>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.") \'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.\' # dates support calendar arithmetic >>> birthday = date(1964, 7, 31) >>> age = now - birthday >>> age.days 14368 10.9 Data Compression Common data archiving and compression formats are directly supported by modules including: zlib, gzip, bz2, zipfile, and tarfile. >>> import zlib >>> s = \'witch which has which witches wrist watch\' >>> len(s) 41 >>> t = zlib.compress(s) >>> len(t) 37 >>> zlib.decompress(t) \'witch which has which witches wrist watch\' >>> zlib.crc32(s) 226805979 10.10 Performance Measurement Some Python users develop a deep interest in knowing the relative performance of different approaches to the same problem. Python provides a measurement tool that answers those questions immediately. For example, it may be tempting to use the tuple packing and unpacking feature instead of the traditional approach to swapping arguments. The timeit module quickly demonstrates a modest performance advantage: >>> from timeit import Timer >>> Timer(\'t=a; a=b; b=t\', \'a=1; b=2\').timeit() 0.57535828626024577 >>> Timer(\'a,b = b,a\', \'a=1; b=2\').timeit() 0.54962537085770791 In contrast to timeit\'s fine level of granularity, the profile and pstats modules provide tools for identifying time critical sections in larger blocks of code. 10.11 Quality Control One approach for developing high quality software is to write tests for each function as it is developed and to run those tests frequently during the development process. The doctest module provides a tool for scanning a module and validating tests embedded in a program\'s docstrings. Test construction is as simple as cutting-and-pasting a typical call along with its results into the docstring. This improves the documentation by providing the user with an example and it allows the doctest module to make sure the code remains true to the documentation: def average(values): """Computes the arithmetic mean of a list of numbers. >>> print average([20, 30, 70]) 40.0 """ return sum(values, 0.0) / len(values) import doctest doctest.testmod() # automatically validate the embedded tests The unittest module is not as effortless as the doctest module, but it allows a more comprehensive set of tests to be maintained in a separate file: import unittest class TestStatisticalFunctions(unittest.TestCase): def test_average(self): self.assertEqual(average([20, 30, 70]), 40.0) self.assertEqual(round(average([1, 5, 7]), 1), 4.3) self.assertRaises(ZeroDivisionError, average, []) self.assertRaises(TypeError, average, 20, 30, 70) unittest.main() # Calling from the command line invokes all tests 10.12 Batteries Included Python has a ``batteries included\'\' philosophy. This is best seen through the sophisticated and robust capabilities of its larger packages. For example: The xmlrpclib and SimpleXMLRPCServer modules make implementing remote procedure calls into an almost trivial task. Despite the modules names, no direct knowledge or handling of XML is needed. The email package is a library for managing email messages, including MIME and other RFC 2822-based message documents. Unlike smtplib and poplib which actually send and receive messages, the email package has a complete toolset for building or decoding complex message structures (including attachments) and for implementing internet encoding and header protocols. The xml.dom and xml.sax packages provide robust support for parsing this popular data interchange format. Likewise, the csv module supports direct reads and writes in a common database format. Together, these modules and packages greatly simplify data interchange between python applications and other tools. Internationalization is supported by a number of modules including gettext, locale, and the codecs package. Python Tutorial Previous: 9. Classes Up: Python Tutorial Next: 11. Br''' >>> hl = Highlighter() >>> out = hl.highlight(teststr, ('print',), ('', '')) xappy-0.5/xappy/indexerconnection.py0000644000175000017500000007607011005453337017575 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""indexerconnection.py: A connection to the search engine for indexing. """ __docformat__ = "restructuredtext en" import _checkxapian import cPickle import xapian from datastructures import * import errors from fieldactions import * import fieldmappings import memutils from replaylog import log class IndexerConnection(object): """A connection to the search engine for indexing. """ def __init__(self, indexpath): """Create a new connection to the index. There may only be one indexer connection for a particular database open at a given time. Therefore, if a connection to the database is already open, this will raise a xapian.DatabaseLockError. If the database doesn't already exist, it will be created. """ self._index = log(xapian.WritableDatabase, indexpath, xapian.DB_CREATE_OR_OPEN) self._indexpath = indexpath # Read existing actions. self._field_actions = {} self._field_mappings = fieldmappings.FieldMappings() self._facet_hierarchy = {} self._facet_query_table = {} self._next_docid = 0 self._config_modified = False self._load_config() # Set management of the memory used. # This can be removed once Xapian implements this itself. self._mem_buffered = 0 self.set_max_mem_use() def set_max_mem_use(self, max_mem=None, max_mem_proportion=None): """Set the maximum memory to use. This call allows the amount of memory to use to buffer changes to be set. This will affect the speed of indexing, but should not result in other changes to the indexing. Note: this is an approximate measure - the actual amount of memory used max exceed the specified amount. Also, note that future versions of xapian are likely to implement this differently, so this setting may be entirely ignored. The absolute amount of memory to use (in bytes) may be set by setting max_mem. Alternatively, the proportion of the available memory may be set by setting max_mem_proportion (this should be a value between 0 and 1). Setting too low a value will result in excessive flushing, and very slow indexing. Setting too high a value will result in excessive buffering, leading to swapping, and very slow indexing. A reasonable default for max_mem_proportion for a system which is dedicated to indexing is probably 0.5: if other tasks are also being performed on the system, the value should be lowered. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if max_mem is not None and max_mem_proportion is not None: raise errors.IndexerError("Only one of max_mem and " "max_mem_proportion may be specified") if max_mem is None and max_mem_proportion is None: self._max_mem = None if max_mem_proportion is not None: physmem = memutils.get_physical_memory() if physmem is not None: max_mem = int(physmem * max_mem_proportion) self._max_mem = max_mem def _store_config(self): """Store the configuration for the database. Currently, this stores the configuration in a file in the database directory, so changes to it are not protected by transactions. When support is available in xapian for storing metadata associated with databases. this will be used instead of a file. """ assert self._index is not None config_str = cPickle.dumps(( self._field_actions, self._field_mappings.serialise(), self._facet_hierarchy, self._facet_query_table, self._next_docid, ), 2) log(self._index.set_metadata, '_xappy_config', config_str) self._config_modified = False def _load_config(self): """Load the configuration for the database. """ assert self._index is not None config_str = log(self._index.get_metadata, '_xappy_config') if len(config_str) == 0: return try: (self._field_actions, mappings, self._facet_hierarchy, self._facet_query_table, self._next_docid) = cPickle.loads(config_str) except ValueError: # Backwards compatibility - configuration used to lack _facet_hierarchy and _facet_query_table (self._field_actions, mappings, self._next_docid) = cPickle.loads(config_str) self._facet_hierarchy = {} self._facet_query_table = {} self._field_mappings = fieldmappings.FieldMappings(mappings) self._config_modified = False def _allocate_id(self): """Allocate a new ID. """ while True: idstr = "%x" % self._next_docid self._next_docid += 1 if not self._index.term_exists('Q' + idstr): break self._config_modified = True return idstr def add_field_action(self, fieldname, fieldtype, **kwargs): """Add an action to be performed on a field. Note that this change to the configuration will not be preserved on disk until the next call to flush(). """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if fieldname in self._field_actions: actions = self._field_actions[fieldname] else: actions = FieldActions(fieldname) self._field_actions[fieldname] = actions actions.add(self._field_mappings, fieldtype, **kwargs) self._config_modified = True def clear_field_actions(self, fieldname): """Clear all actions for the specified field. This does not report an error if there are already no actions for the specified field. Note that this change to the configuration will not be preserved on disk until the next call to flush(). """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if fieldname in self._field_actions: del self._field_actions[fieldname] self._config_modified = True def get_fields_with_actions(self): """Get a list of field names which have actions defined. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") return self._field_actions.keys() def process(self, document): """Process an UnprocessedDocument with the settings in this database. The resulting ProcessedDocument is returned. Note that this processing will be automatically performed if an UnprocessedDocument is supplied to the add() or replace() methods of IndexerConnection. This method is exposed to allow the processing to be performed separately, which may be desirable if you wish to manually modify the processed document before adding it to the database, or if you want to split processing of documents from adding documents to the database for performance reasons. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") result = ProcessedDocument(self._field_mappings) result.id = document.id context = ActionContext(self._index) for field in document.fields: try: actions = self._field_actions[field.name] except KeyError: # If no actions are defined, just ignore the field. continue actions.perform(result, field.value, context) return result def _get_bytes_used_by_doc_terms(self, xapdoc): """Get an estimate of the bytes used by the terms in a document. (This is a very rough estimate.) """ count = 0 for item in xapdoc.termlist(): # The term may also be stored in the spelling correction table, so # double the amount used. count += len(item.term) * 2 # Add a few more bytes for holding the wdf, and other bits and # pieces. count += 8 # Empirical observations indicate that about 5 times as much memory as # the above calculation predicts is used for buffering in practice. return count * 5 def add(self, document): """Add a new document to the search engine index. If the document has a id set, and the id already exists in the database, an exception will be raised. Use the replace() method instead if you wish to overwrite documents. Returns the id of the newly added document (making up a new unique ID if no id was set). The supplied document may be an instance of UnprocessedDocument, or an instance of ProcessedDocument. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if not hasattr(document, '_doc'): # It's not a processed document. document = self.process(document) # Ensure that we have a id orig_id = document.id if orig_id is None: id = self._allocate_id() document.id = id else: id = orig_id if self._index.term_exists('Q' + id): raise errors.IndexerError("Document ID of document supplied to add() is not unique.") # Add the document. xapdoc = document.prepare() self._index.add_document(xapdoc) if self._max_mem is not None: self._mem_buffered += self._get_bytes_used_by_doc_terms(xapdoc) if self._mem_buffered > self._max_mem: self.flush() if id is not orig_id: document.id = orig_id return id def replace(self, document): """Replace a document in the search engine index. If the document does not have a id set, an exception will be raised. If the document has a id set, and the id does not already exist in the database, this method will have the same effect as add(). """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if not hasattr(document, '_doc'): # It's not a processed document. document = self.process(document) # Ensure that we have a id id = document.id if id is None: raise errors.IndexerError("No document ID set for document supplied to replace().") xapdoc = document.prepare() self._index.replace_document('Q' + id, xapdoc) if self._max_mem is not None: self._mem_buffered += self._get_bytes_used_by_doc_terms(xapdoc) if self._mem_buffered > self._max_mem: self.flush() def _make_synonym_key(self, original, field): """Make a synonym key (ie, the term or group of terms to store in xapian). """ if field is not None: prefix = self._field_mappings.get_prefix(field) else: prefix = '' original = original.lower() # Add the prefix to the start of each word. return ' '.join((prefix + word for word in original.split(' '))) def add_synonym(self, original, synonym, field=None, original_field=None, synonym_field=None): """Add a synonym to the index. - `original` is the word or words which will be synonym expanded in searches (if multiple words are specified, each word should be separated by a single space). - `synonym` is a synonym for `original`. - `field` is the field which the synonym is specific to. If no field is specified, the synonym will be used for searches which are not specific to any particular field. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if original_field is None: original_field = field if synonym_field is None: synonym_field = field key = self._make_synonym_key(original, original_field) # FIXME - this only works for exact fields which have no upper case # characters, or single words value = self._make_synonym_key(synonym, synonym_field) self._index.add_synonym(key, value) def remove_synonym(self, original, synonym, field=None): """Remove a synonym from the index. - `original` is the word or words which will be synonym expanded in searches (if multiple words are specified, each word should be separated by a single space). - `synonym` is a synonym for `original`. - `field` is the field which this synonym is specific to. If no field is specified, the synonym will be used for searches which are not specific to any particular field. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") key = self._make_synonym_key(original, field) self._index.remove_synonym(key, synonym.lower()) def clear_synonyms(self, original, field=None): """Remove all synonyms for a word (or phrase). - `field` is the field which this synonym is specific to. If no field is specified, the synonym will be used for searches which are not specific to any particular field. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") key = self._make_synonym_key(original, field) self._index.clear_synonyms(key) def _assert_facet(self, facet): """Raise an error if facet is not a declared facet field. """ for action in self._field_actions[facet]._actions: if action == FieldActions.FACET: return raise errors.IndexerError("Field %r is not indexed as a facet" % facet) def add_subfacet(self, subfacet, facet): """Add a subfacet-facet relationship to the facet hierarchy. Any existing relationship for that subfacet is replaced. Raises a KeyError if either facet or subfacet is not a field, and an IndexerError if either facet or subfacet is not a facet field. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") self._assert_facet(facet) self._assert_facet(subfacet) self._facet_hierarchy[subfacet] = facet self._config_modified = True def remove_subfacet(self, subfacet): """Remove any existing facet hierarchy relationship for a subfacet. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if subfacet in self._facet_hierarchy: del self._facet_hierarchy[subfacet] self._config_modified = True def get_subfacets(self, facet): """Get a list of subfacets of a facet. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") return [k for k, v in self._facet_hierarchy.iteritems() if v == facet] FacetQueryType_Preferred = 1; FacetQueryType_Never = 2; def set_facet_for_query_type(self, query_type, facet, association): """Set the association between a query type and a facet. The value of `association` must be one of IndexerConnection.FacetQueryType_Preferred, IndexerConnection.FacetQueryType_Never or None. A value of None removes any previously set association. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if query_type is None: raise errors.IndexerError("Cannot set query type information for None") self._assert_facet(facet) if query_type not in self._facet_query_table: self._facet_query_table[query_type] = {} if association is None: if facet in self._facet_query_table[query_type]: del self._facet_query_table[query_type][facet] else: self._facet_query_table[query_type][facet] = association; if self._facet_query_table[query_type] == {}: del self._facet_query_table[query_type] self._config_modified = True def get_facets_for_query_type(self, query_type, association): """Get the set of facets associated with a query type. Only those facets associated with the query type in the specified manner are returned; `association` must be one of IndexerConnection.FacetQueryType_Preferred or IndexerConnection.FacetQueryType_Never. If the query type has no facets associated with it, None is returned. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if query_type not in self._facet_query_table: return None facet_dict = self._facet_query_table[query_type] return set([facet for facet, assoc in facet_dict.iteritems() if assoc == association]) def set_metadata(self, key, value): """Set an item of metadata stored in the connection. The value supplied will be returned by subsequent calls to get_metadata() which use the same key. Keys with a leading underscore are reserved for internal use - you should not use such keys unless you really know what you are doing. This will store the value supplied in the database. It will not be visible to readers (ie, search connections) until after the next flush. The key is limited to about 200 characters (the same length as a term is limited to). The value can be several megabytes in size. To remove an item of metadata, simply call this with a `value` parameter containing an empty string. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if not hasattr(self._index, 'set_metadata'): raise errors.IndexerError("Version of xapian in use does not support metadata") log(self._index.set_metadata, key, value) def get_metadata(self, key): """Get an item of metadata stored in the connection. This returns a value stored by a previous call to set_metadata. If the value is not found, this will return the empty string. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if not hasattr(self._index, 'get_metadata'): raise errors.IndexerError("Version of xapian in use does not support metadata") return log(self._index.get_metadata, key) def delete(self, id): """Delete a document from the search engine index. If the id does not already exist in the database, this method will have no effect (and will not report an error). """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") self._index.delete_document('Q' + id) def flush(self): """Apply recent changes to the database. If an exception occurs, any changes since the last call to flush() may be lost. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if self._config_modified: self._store_config() self._index.flush() self._mem_buffered = 0 def close(self): """Close the connection to the database. It is important to call this method before allowing the class to be garbage collected, because it will ensure that any un-flushed changes will be flushed. It also ensures that the connection is cleaned up promptly. No other methods may be called on the connection after this has been called. (It is permissible to call close() multiple times, but only the first call will have any effect.) If an exception occurs, the database will be closed, but changes since the last call to flush may be lost. """ if self._index is None: return try: self.flush() finally: # There is currently no "close()" method for xapian databases, so # we have to rely on the garbage collector. Since we never copy # the _index property out of this class, there should be no cycles, # so the standard python implementation should garbage collect # _index straight away. A close() method is planned to be added to # xapian at some point - when it is, we should call it here to make # the code more robust. self._index = None self._indexpath = None self._field_actions = None self._config_modified = False def get_doccount(self): """Count the number of documents in the database. This count will include documents which have been added or removed but not yet flushed(). """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") return self._index.get_doccount() def iterids(self): """Get an iterator which returns all the ids in the database. The unqiue_ids are currently returned in binary lexicographical sort order, but this should not be relied on. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") return PrefixedTermIter('Q', self._index.allterms()) def get_document(self, id): """Get the document with the specified unique ID. Raises a KeyError if there is no such document. Otherwise, it returns a ProcessedDocument. """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") postlist = self._index.postlist('Q' + id) try: plitem = postlist.next() except StopIteration: # Unique ID not found raise KeyError('Unique ID %r not found' % id) try: postlist.next() raise errors.IndexerError("Multiple documents " #pragma: no cover "found with same unique ID") except StopIteration: # Only one instance of the unique ID found, as it should be. pass result = ProcessedDocument(self._field_mappings) result.id = id result._doc = self._index.get_document(plitem.docid) return result def iter_synonyms(self, prefix=""): """Get an iterator over the synonyms. - `prefix`: if specified, only synonym keys with this prefix will be returned. The iterator returns 2-tuples, in which the first item is the key (ie, a 2-tuple holding the term or terms which will be synonym expanded, followed by the fieldname specified (or None if no fieldname)), and the second item is a tuple of strings holding the synonyms for the first item. These return values are suitable for the dict() builtin, so you can write things like: >>> conn = IndexerConnection('foo') >>> conn.add_synonym('foo', 'bar') >>> conn.add_synonym('foo bar', 'baz') >>> conn.add_synonym('foo bar', 'foo baz') >>> dict(conn.iter_synonyms()) {('foo', None): ('bar',), ('foo bar', None): ('baz', 'foo baz')} """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") return SynonymIter(self._index, self._field_mappings, prefix) def iter_subfacets(self): """Get an iterator over the facet hierarchy. The iterator returns 2-tuples, in which the first item is the subfacet and the second item is its parent facet. The return values are suitable for the dict() builtin, for example: >>> conn = IndexerConnection('db') >>> conn.add_field_action('foo', FieldActions.FACET) >>> conn.add_field_action('bar', FieldActions.FACET) >>> conn.add_field_action('baz', FieldActions.FACET) >>> conn.add_subfacet('foo', 'bar') >>> conn.add_subfacet('baz', 'bar') >>> dict(conn.iter_subfacets()) {'foo': 'bar', 'baz': 'bar'} """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if 'facets' in _checkxapian.missing_features: raise errors.IndexerError("Facets unsupported with this release of xapian") return self._facet_hierarchy.iteritems() def iter_facet_query_types(self, association): """Get an iterator over query types and their associated facets. Only facets associated with the query types in the specified manner are returned; `association` must be one of IndexerConnection.FacetQueryType_Preferred or IndexerConnection.FacetQueryType_Never. The iterator returns 2-tuples, in which the first item is the query type and the second item is the associated set of facets. The return values are suitable for the dict() builtin, for example: >>> conn = IndexerConnection('db') >>> conn.add_field_action('foo', FieldActions.FACET) >>> conn.add_field_action('bar', FieldActions.FACET) >>> conn.add_field_action('baz', FieldActions.FACET) >>> conn.set_facet_for_query_type('type1', 'foo', conn.FacetQueryType_Preferred) >>> conn.set_facet_for_query_type('type1', 'bar', conn.FacetQueryType_Never) >>> conn.set_facet_for_query_type('type1', 'baz', conn.FacetQueryType_Never) >>> conn.set_facet_for_query_type('type2', 'bar', conn.FacetQueryType_Preferred) >>> dict(conn.iter_facet_query_types(conn.FacetQueryType_Preferred)) {'type1': set(['foo']), 'type2': set(['bar'])} >>> dict(conn.iter_facet_query_types(conn.FacetQueryType_Never)) {'type1': set(['bar', 'baz'])} """ if self._index is None: raise errors.IndexerError("IndexerConnection has been closed") if 'facets' in _checkxapian.missing_features: raise errors.IndexerError("Facets unsupported with this release of xapian") return FacetQueryTypeIter(self._facet_query_table, association) class PrefixedTermIter(object): """Iterate through all the terms with a given prefix. """ def __init__(self, prefix, termiter): """Initialise the prefixed term iterator. - `prefix` is the prefix to return terms for. - `termiter` is a xapian TermIterator, which should be at its start. """ # The algorithm used in next() currently only works for single # character prefixes, so assert that the prefix is single character. # To deal with multicharacter prefixes, we need to check for terms # which have a starting prefix equal to that given, but then have a # following uppercase alphabetic character, indicating that the actual # prefix is longer than the target prefix. We then need to skip over # these. Not too hard to implement, but we don't need it yet. assert(len(prefix) == 1) self._started = False self._prefix = prefix self._prefixlen = len(prefix) self._termiter = termiter def __iter__(self): return self def next(self): """Get the next term with the specified prefix. """ if not self._started: term = self._termiter.skip_to(self._prefix).term self._started = True else: term = self._termiter.next().term if len(term) < self._prefixlen or term[:self._prefixlen] != self._prefix: raise StopIteration return term[self._prefixlen:] class SynonymIter(object): """Iterate through a list of synonyms. """ def __init__(self, index, field_mappings, prefix): """Initialise the synonym iterator. - `index` is the index to get the synonyms from. - `field_mappings` is the FieldMappings object for the iterator. - `prefix` is the prefix to restrict the returned synonyms to. """ self._index = index self._field_mappings = field_mappings self._syniter = self._index.synonym_keys(prefix) def __iter__(self): return self def next(self): """Get the next synonym. """ synkey = self._syniter.next() pos = 0 for char in synkey: if char.isupper(): pos += 1 else: break if pos == 0: fieldname = None terms = synkey else: prefix = synkey[:pos] fieldname = self._field_mappings.get_fieldname_from_prefix(prefix) terms = ' '.join((term[pos:] for term in synkey.split(' '))) synval = tuple(self._index.synonyms(synkey)) return ((terms, fieldname), synval) class FacetQueryTypeIter(object): """Iterate through all the query types and their associated facets. """ def __init__(self, facet_query_table, association): """Initialise the query type facet iterator. Only facets associated with each query type in the specified manner are returned (`association` must be one of IndexerConnection.FacetQueryType_Preferred or IndexerConnection.FacetQueryType_Never). """ self._table_iter = facet_query_table.iteritems() self._association = association def __iter__(self): return self def next(self): """Get the next (query type, facet set) 2-tuple. """ query_type, facet_dict = self._table_iter.next() facet_list = [facet for facet, association in facet_dict.iteritems() if association == self._association] if len(facet_list) == 0: return self.next() return (query_type, set(facet_list)) if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/xappy/indexerconnection_doctest1.txt0000644000175000017500000001605410722552030021561 0ustar richardrichard >>> from datastructures import * >>> from fieldactions import * Open a connection for indexing: >>> conn = IndexerConnection('foo') There can only be one IndexerConnection in existence for a given path at a time: >>> conn = IndexerConnection('foo') #doctest:+ELLIPSIS Traceback (most recent call last): ... DatabaseLockError: Unable to acquire database write lock on foo... We should have no documents in the database yet: >>> conn.get_doccount() 0 Add some field actions to the database: >>> conn.add_field_action('author', FieldActions.STORE_CONTENT) >>> conn.add_field_action('author', FieldActions.INDEX_EXACT) >>> conn.add_field_action('title', FieldActions.INDEX_FREETEXT) We can't index as both EXACT and FREETEXT: >>> conn.add_field_action('author', FieldActions.INDEX_FREETEXT, weight=5, language='en') Traceback (most recent call last): ... IndexerError: Field 'author' is already marked for indexing as exact text: cannot mark for indexing as free text as well >>> conn.add_field_action('title', FieldActions.INDEX_EXACT) Traceback (most recent call last): ... IndexerError: Field 'title' is already marked for indexing as free text: cannot mark for indexing as exact text as well We can add multiple STORE_CONTENT actions though (subsequent ones have no further effect). >>> conn.add_field_action('author', FieldActions.STORE_CONTENT) Field actions are checked for basic validity: >>> conn.add_field_action('author', None) Traceback (most recent call last): ... IndexerError: Unknown field action: None >>> conn.add_field_action('author', FieldActions.STORE_CONTENT, foo=1) Traceback (most recent call last): ... IndexerError: Unknown parameter name for action 'STORE_CONTENT': 'foo' We can ensure there are no actions for a given field by using clear_field_actions(): >>> conn.clear_field_actions('title') This doesn't complain even if we've never mentioned the field before: >>> conn.clear_field_actions('foo') Then we can add a field action back again: >>> conn.add_field_action('title', FieldActions.INDEX_FREETEXT, weight=10, language='en') We have to wipe out any old actions on the field to change the actions: >>> conn.clear_field_actions('author') >>> conn.add_field_action('author', FieldActions.STORE_CONTENT) >>> conn.add_field_action('author', FieldActions.INDEX_FREETEXT, weight=5, language='en') >>> conn.clear_field_actions('title') >>> conn.add_field_action('title', FieldActions.INDEX_EXACT) We should have no documents in the database yet: >>> conn.get_doccount() 0 Build up a document: >>> doc = UnprocessedDocument() We can add field instances. Multiple instances of a field are valid. >>> doc.fields.append(Field('author', 'Richard Boulton')) >>> doc.fields.append(Field('author', 'Charlie Hull')) >>> doc.fields.append(Field('title', 'Test document')) We can get a vaguely pretty display of the contents of an UnprocessedDocument(): >>> print doc UnprocessedDocument(None, [Field('author', 'Richard Boulton'), Field('author', 'Charlie Hull'), Field('title', 'Test document')]) We can process a document explicitly, if we want to. >>> pdoc = conn.process(doc) Only the "author" field appears in the output, because only it was given the action STORE_CONTENT. >>> pdoc.data {'author': ['Richard Boulton', 'Charlie Hull']} We can access the xapian document representation of the processed document: >>> xdoc = pdoc.prepare() >>> import cPickle >>> cPickle.loads(xdoc.get_data()) {'author': ['Richard Boulton', 'Charlie Hull']} >>> [(term.term, term.wdf, [pos for pos in term.positer]) for term in xdoc.termlist()] [('XAboulton', 5, [2]), ('XAcharlie', 5, [13]), ('XAhull', 5, [14]), ('XArichard', 5, [1]), ('XB:Test document', 0, []), ('ZXAboulton', 5, []), ('ZXAcharli', 5, []), ('ZXAhull', 5, []), ('ZXArichard', 5, []), ('Zboulton', 5, []), ('Zcharli', 5, []), ('Zhull', 5, []), ('Zrichard', 5, []), ('boulton', 5, [2]), ('charlie', 5, [13]), ('hull', 5, [14]), ('richard', 5, [1])] Adding the same document multiple times is fine if it doesn't have an id assigned to it: a new ID will be allocated for each addition: >>> conn.add(doc) '0' >>> conn.add(doc) '1' >>> conn.add(doc) '2' >>> conn.get_doccount() 3 We can set the unique ID ourselves, if we want: >>> print repr(doc.id) None >>> doc.id = '4' >>> print repr(doc.id) '4' >>> conn.add(doc) '4' >>> conn.get_doccount() 4 If we try adding a document with a unique ID which already exists we get an error: >>> doc.id = '1' >>> print repr(doc.id) '1' >>> conn.add(doc) Traceback (most recent call last): ... IndexerError: Document ID of document supplied to add() is not unique. >>> conn.get_doccount() 4 If we remove the id, it works again: >>> doc.id = None >>> print repr(doc.id) None >>> conn.add(doc) '3' >>> conn.get_doccount() 5 But it skips ID 4 because we manually added a document with that ID. >>> conn.add(doc) '5' >>> conn.get_doccount() 6 Unique IDs don't have to be numbers: we can set them to anything we like. >>> doc.id = 'SuperFoo' >>> print repr(doc.id) 'SuperFoo' >>> conn.add(doc) 'SuperFoo' >>> conn.get_doccount() 7 We can delete documents by specifying the unique ID. >>> conn.delete('5') >>> conn.get_doccount() 6 Finally, we have to flush to apply the changes: >>> conn.flush() We can add more documents after the flush: >>> doc.id = None >>> conn.add(doc) '6' >>> conn.get_doccount() 7 We can add fields which don't have any configuration. These will be ignored. >>> doc.fields.append(Field('text', 'Some boring text')) >>> conn.add(doc) '7' >>> conn.get_doccount() 8 We can also supply fields as an iterator instead of a list: >>> fieldlist = [Field('author', 'Richard Boulton')] >>> doc.fields = iter(fieldlist) >>> conn.add(doc) '8' >>> conn.get_doccount() 9 Calling close() will automatically call flush(), too: >>> conn.close() After calling close(), no other methods are valid: >>> conn.add_field_action('title', FieldActions.INDEX_FREETEXT, weight=10, language='en') Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.clear_field_actions('author') Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.process(doc) Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.add(doc) Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.replace(doc) Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.delete('1') Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.flush() Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.get_doccount() Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.iterids() Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed >>> conn.get_document('1') Traceback (most recent call last): ... IndexerError: IndexerConnection has been closed But calling close() multiple times is okay: >>> conn.close() Now that we've closed the connection, we can open a new one: >>> conn = IndexerConnection('foo') >>> conn.get_doccount() 9 xappy-0.5/xappy/indexerconnection_doctest2.txt0000644000175000017500000003705710725037616021603 0ustar richardrichard >>> from datastructures import * >>> from fieldactions import * >>> from searchconnection import * Open a connection for indexing: >>> iconn = IndexerConnection('foo') We should have no documents in the database yet: >>> iconn.get_doccount() 0 We have to wipe out any old actions on the field to change the actions: >>> iconn.add_field_action('author', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('title', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('title', FieldActions.INDEX_FREETEXT, weight=5, language='en') >>> iconn.add_field_action('category', FieldActions.INDEX_EXACT) >>> iconn.add_field_action('category', FieldActions.SORTABLE) >>> iconn.add_field_action('category', FieldActions.COLLAPSE) >>> iconn.add_field_action('text', FieldActions.INDEX_FREETEXT, language='en') >>> iconn.add_field_action('other', FieldActions.INDEX_FREETEXT) Build up a document: >>> doc = UnprocessedDocument() We can add field instances. Multiple instances of a field are valid. >>> doc.fields.append(Field('author', 'Richard Boulton')) >>> doc.fields.append(Field('category', 'Test document')) >>> doc.fields.append(Field('title', 'Test document 1')) >>> doc.fields.append(Field('text', 'This document is a basic test document.')) We can process a document explicitly, if we want to. >>> pdoc = iconn.process(doc) >>> pdoc.data {'title': ['Test document 1'], 'author': ['Richard Boulton']} We can access the Xapian document representation of the processed document to double check that this document has been indexed as we wanted: >>> xdoc = pdoc.prepare() >>> import cPickle >>> cPickle.loads(xdoc.get_data()) == pdoc.data True >>> [(term.term, term.wdf, [pos for pos in term.positer]) for term in xdoc.termlist()] [('1', 5, [3]), ('XA1', 5, [3]), ('XAdocument', 5, [2]), ('XAtest', 5, [1]), ('XB:Test document', 0, []), ('XCa', 1, [17]), ('XCbasic', 1, [18]), ('XCdocument', 2, [15, 20]), ('XCis', 1, [16]), ('XCtest', 1, [19]), ('XCthis', 1, [14]), ('ZXAdocument', 5, []), ('ZXAtest', 5, []), ('ZXCa', 1, []), ('ZXCbasic', 1, []), ('ZXCdocument', 2, []), ('ZXCis', 1, []), ('ZXCtest', 1, []), ('ZXCthis', 1, []), ('Za', 1, []), ('Zbasic', 1, []), ('Zdocument', 7, []), ('Zis', 1, []), ('Ztest', 6, []), ('Zthis', 1, []), ('a', 1, [17]), ('basic', 1, [18]), ('document', 7, [2, 15, 20]), ('is', 1, [16]), ('test', 6, [1, 19]), ('this', 1, [14])] >>> [(value.num, value.value) for value in xdoc.values()] [(0, 'Test document')] >>> ','.join(iconn.iterids()) '' >>> iconn.add(pdoc) '0' >>> sconn1 = SearchConnection('foo') >>> ','.join(iconn.iterids()) '0' Regression test: if we called add with a ProcessedDocument which didn't have a unique ID, the generated ID used to get assigned to the ProcessedDocument. This shouldn't happen. >>> print pdoc.id None >>> iconn.add(pdoc) '1' >>> pdoc.id = 'B' >>> iconn.add(pdoc) 'B' >>> iconn.get_doccount() 3 Add some more documents: >>> doc = UnprocessedDocument(fields=(Field('author', 'Charlie Hull'), ... Field('category', 'Silly Document'), ... Field('text', 'Charlie is a juggler'), ... Field('other', 'Some other content.'), ... )) >>> iconn.add(doc) '2' >>> doc = UnprocessedDocument(fields=(Field('author', 'Charlie Hull'), ... Field('category', 'Juggling'), ... Field('text', '5 clubs is quite hard.'), ... )) >>> iconn.add(doc) '3' >>> doc = UnprocessedDocument(fields=(Field('author', 'Charlie Hull'), ... Field('category', 'Juggling'), ... Field('text', 'Good toilets are important at juggling festivals'), ... )) >>> iconn.add(doc) '4' >>> iconn.get_doccount() 6 Now, try searching it: There's nothing in the database, because the changes haven't been flushed. >>> sconn1.get_doccount() 0 The iconn can access the same documents before and after a flush: >>> ','.join(iconn.iterids()) '0,1,2,3,4,B' >>> iconn.flush() >>> ','.join(iconn.iterids()) '0,1,2,3,4,B' The open connection still accesses the same revision, so there are still no documents visible: >>> sconn1.get_doccount() 0 A new connection can see the documents, though: >>> sconn2 = SearchConnection('foo') >>> sconn2.get_doccount() 6 >>> doc = UnprocessedDocument(fields=(Field('author', 'Richard Boulton'), ... Field('category', 'Gardening'), ... Field('text', 'Clematis grows very fast, and may smother other plants'), ... )) >>> iconn.add(doc) '5' >>> iconn.get_doccount() 7 The current search connection can't see the new document: >>> sconn2.get_doccount() 6 After a flush, the old connections still can't see the new document: >>> iconn.flush() >>> sconn1.get_doccount() 0 >>> sconn2.get_doccount() 6 A new connection can see the new document: >>> sconn3 = SearchConnection('foo') >>> sconn3.get_doccount() 7 Let's try deleting a document: >>> iconn.delete('5') >>> iconn.get_doccount() 6 After a flush, a new connection can see the change: >>> iconn.flush() >>> sconn4 = SearchConnection('foo') >>> sconn1.get_doccount() 0 >>> sconn2.get_doccount() 6 >>> sconn3.get_doccount() 7 >>> sconn4.get_doccount() 6 If we reopen the connection, we can see the latest changes: >>> sconn1.reopen() >>> sconn1.get_doccount() 6 We can parse some >>> str(sconn4.query_parse('test')) 'Xapian::Query((Ztest:(pos=1) AND_MAYBE test:(pos=1)))' >>> str(sconn4.query_parse('title:test')) 'Xapian::Query((ZXAtest:(pos=1) AND_MAYBE XAtest:(pos=1)))' >>> str(sconn4.query_parse('title:Test')) 'Xapian::Query((XAtest:(pos=1) AND_MAYBE XAtest:(pos=1)))' Xapian needs a patch to support exact prefixes. When this is applied, the following test will pass. >> str(sconn4.query_parse('title:Test category:Te/st')) 'Xapian::Query((XAtest:(pos=1) AND XB:Te/st:(pos=2)))' For now, the output is approximately right, and good enough to be going on with: >>> str(sconn4.query_parse('title:Test category:Te/st')) 'Xapian::Query(((XAtest:(pos=1) AND (XBte:(pos=2) PHRASE 2 XBst:(pos=3))) AND_MAYBE (XAtest:(pos=1) AND (XBte:(pos=2) PHRASE 2 XBst:(pos=3)))))' >>> q1 = sconn4.query_parse('text:(clematis)') >>> q2 = sconn4.query_parse('title:Test') >>> str(sconn4.query_filter(q1, q2)) 'Xapian::Query(((ZXCclemati:(pos=1) AND_MAYBE XCclematis:(pos=1)) FILTER (XAtest:(pos=1) AND_MAYBE XAtest:(pos=1))))' >>> str(sconn4.query_filter(q1, "filter")) Traceback (most recent call last): ... SearchError: Filter must be a Xapian Query object If we only allow a limited set of fields, other field specifications will be considered as plain text: >>> str(sconn4.query_parse("text:clematis title:Test")) 'Xapian::Query(((ZXCclemati:(pos=1) AND XAtest:(pos=2)) AND_MAYBE (XCclematis:(pos=1) AND XAtest:(pos=2))))' >>> str(sconn4.query_parse("text:clematis title:Test", allow=("text",))) 'Xapian::Query(((ZXCclemati:(pos=1) AND (title:(pos=2) PHRASE 2 test:(pos=3))) AND_MAYBE (XCclematis:(pos=1) AND (title:(pos=2) PHRASE 2 test:(pos=3)))))' >>> str(sconn4.query_parse("text:clematis title:Test", deny=("title",))) 'Xapian::Query(((ZXCclemati:(pos=1) AND (title:(pos=2) PHRASE 2 test:(pos=3))) AND_MAYBE (XCclematis:(pos=1) AND (title:(pos=2) PHRASE 2 test:(pos=3)))))' >>> str(sconn4.query_parse("text:clematis title:Test", allow=("text",), deny=("title",))) Traceback (most recent call last): ... SearchError: Cannot specify both `allow` and `deny` (got ('text',) and ('title',)) We can parse queries which don't specify a field explicitly, too: >>> str(sconn4.query_parse("clematis Test")) 'Xapian::Query(((Zclemati:(pos=1) AND test:(pos=2)) AND_MAYBE (clematis:(pos=1) AND test:(pos=2))))' We can generate a query for an individual field: >>> str(sconn4.query_field('text', "clematis Test")) 'Xapian::Query(((ZXCclemati:(pos=1) AND XCtest:(pos=2)) AND_MAYBE (XCclematis:(pos=1) AND XCtest:(pos=2))))' If we generate a query for a field with no language set, it won't be stemmed: >>> str(sconn4.query_field('other', "clematis Test")) 'Xapian::Query(((XDclematis:(pos=1) AND XDtest:(pos=2)) AND_MAYBE (XDclematis:(pos=1) AND XDtest:(pos=2))))' If the field is an exact text field, the query will contain a single term: >>> str(sconn4.query_field('category', "Clematis Test")) 'Xapian::Query(XB:Clematis Test)' If the field isn't known, we get an empty query: >>> q2 = sconn4.query_field('unknown', "clematis Test") >>> str(q2) 'Xapian::Query()' If we filter a query with an empty query, we get another empty query: >>> str(sconn4.query_filter(q1, q2)) 'Xapian::Query()' >>> q = sconn4.query_parse('title:Test') >>> str(q) 'Xapian::Query((XAtest:(pos=1) AND_MAYBE XAtest:(pos=1)))' >>> res = sconn4.search(q, 0, 10) >>> res.matches_lower_bound 3 >>> res.matches_upper_bound 3 >>> res.matches_estimated 3 >>> res.estimate_is_exact True >>> res.more_matches False >>> str(res) '' If we ask for fewer results, we get them: >>> res = sconn4.search(q, 0, 2) >>> str(res) '' >>> res = sconn4.search(q, 0, 3) >>> str(res) '' Multiword queries use AND to combine terms, by default: >>> q1 = sconn4.query_parse('text:(important plants)') >>> str(q1) 'Xapian::Query(((ZXCimport:(pos=1) AND ZXCplant:(pos=2)) AND_MAYBE (XCimportant:(pos=1) AND XCplants:(pos=2))))' But we can set the default operator to OR if we want: >>> q1 = sconn4.query_parse('text:(important plants)', default_op=sconn4.OP_OR) >>> str(q1) 'Xapian::Query(((ZXCimport:(pos=1) OR ZXCplant:(pos=2)) AND_MAYBE (XCimportant:(pos=1) OR XCplants:(pos=2))))' We can combine queries: >>> q2 = sconn4.query_parse('title:test') >>> q = sconn4.query_composite(sconn4.OP_OR, (q1, q2)) >>> str(q) 'Xapian::Query((((ZXCimport:(pos=1) OR ZXCplant:(pos=2)) AND_MAYBE (XCimportant:(pos=1) OR XCplants:(pos=2))) OR (ZXAtest:(pos=1) AND_MAYBE XAtest:(pos=1))))' >>> doc = UnprocessedDocument(fields=(Field('author', 'Richard Boulton'), ... Field('category', 'Gardening'), ... Field('text', 'Clematis grows very fast, and may smother other plants'), ... )) >>> for i in xrange(100): ... id = iconn.add(doc) >>> iconn.flush() >>> sconn1.reopen() >>> sconn2.reopen() >>> sconn1.search(q, 0, 3) We can perform the same search again after more modifications have been made, and we get the same result: >>> for i in xrange(100): ... id = iconn.add(doc) >>> iconn.flush() >>> results1 = sconn1.search(q, 0, 3) >>> results1 But if further modifications have been made, the searcher has to be reopened, so a different result set is returned. >>> for i in xrange(100): ... id = iconn.add(doc) >>> iconn.flush() >>> results2 = sconn1.search(q, 0, 50) >>> results2 We can get the details of the hit at a given rank: >>> hit = results1.get_hit(2) >>> hit.rank 2 >>> hit.id 'B' >>> hit.data {'title': ['Test document 1'], 'author': ['Richard Boulton']} >>> str(hit) "" >>> str(results2.get_hit(2)) "" >>> str(results2.get_hit(49)) "" We can change a document in the index, and the old result is still available: >>> newdoc = UnprocessedDocument(fields=(Field('author', 'Fred Bloggs'), ... Field('category', 'Sleeping'), ... Field('text', 'This is different text to before'),), ... id=results2.get_hit(49).id) >>> iconn.replace(newdoc) (If we don't set an ID, we get an error. >>> newdoc = UnprocessedDocument(fields=(Field('author', 'Freda Bloggs'), ... Field('category', 'Sleeping'), ... Field('text', 'This is different text to before'),)) >>> iconn.replace(newdoc) Traceback (most recent call last): ... IndexerError: No document ID set for document supplied to replace(). >>> iconn.flush() >>> str(results2.get_hit(49)) "" But on a newly reopened connection, the result is gone (note the different id): >>> sconn2.reopen() >>> results3 = sconn2.search(q, 0, 50) >>> str(results3.get_hit(49)) "" We can get a list of the current document IDs >>> print [id for id in iconn.iterids()][:10] ['0', '1', '10', '100', '101', '102', '103', '104', '105', '106'] >>> pdoc = iconn.get_document('0') >>> print pdoc.data {'title': ['Test document 1'], 'author': ['Richard Boulton']} If we perform major changes on the database, the results of a search might become unavailable: >>> sconn1.reopen() >>> results4 = sconn1.search(q, 0, 100) >>> for id in iconn.iterids(): ... iconn.delete(id) >>> iconn.get_doccount() 0 >>> iconn.flush() >>> iconn.get_doccount() 0 >>> for i in xrange(100): ... id = iconn.add(doc) >>> iconn.flush() >>> for i in xrange(100): ... id = iconn.add(doc) >>> iconn.flush() >>> for hit in results4: pass Traceback (most recent call last): ... DatabaseModifiedError: The revision being read has been discarded - you should call Xapian::Database::reopen() and retry the operation When we're finished with the connection, we can close it to release the resources: >>> sconn1.close() Repeated closing is okay: >>> sconn1.close() After closing, no other methods should be called: >>> sconn1.reopen() Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.get_doccount() Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.query_composite(sconn1.OP_AND, 'foo') Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.query_filter(q, q) Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.query_range('date', '19991212', '20000101') Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.query_parse('hello') Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.query_field('author', 'richard') Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.query_facet('author', 'richard') Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.search(q, 0, 10) Traceback (most recent call last): ... SearchError: SearchConnection has been closed >>> sconn1.get_document('1') Traceback (most recent call last): ... SearchError: SearchConnection has been closed But calling close() multiple times is okay: >>> sconn1.close() xappy-0.5/xappy/indexerconnection_doctest3.txt0000644000175000017500000001162710667526666021614 0ustar richardrichard >>> from datastructures import * >>> from fieldactions import * >>> from searchconnection import * Open a connection for indexing: >>> iconn = IndexerConnection('foo') We have to wipe out any old actions on the field to change the actions: >>> iconn.add_field_action('author', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('title', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('title', FieldActions.INDEX_FREETEXT, weight=5, language='en', nopos=True) >>> iconn.add_field_action('category', FieldActions.INDEX_EXACT) >>> iconn.add_field_action('category', FieldActions.SORTABLE) >>> iconn.add_field_action('category', FieldActions.COLLAPSE) >>> iconn.add_field_action('text', FieldActions.INDEX_FREETEXT, language='en') >>> iconn.add_field_action('other', FieldActions.INDEX_FREETEXT) >>> iconn.add_field_action('date', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('date', FieldActions.SORTABLE, type='date') >>> iconn.add_field_action('date', FieldActions.COLLAPSE) >>> iconn.add_field_action('price', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('price', FieldActions.SORTABLE, type='float') >>> iconn.add_field_action('price', FieldActions.COLLAPSE) Build up a document: >>> doc = UnprocessedDocument() >>> doc.fields.append(Field('author', 'Richard Boulton')) >>> doc.fields.append(Field('category', 'Test document')) >>> doc.fields.append(Field('title', 'Test document 1')) >>> doc.fields.append(Field('text', 'This document is a basic test document.')) Process it: >>> pdoc = iconn.process(doc) >>> pdoc.data {'title': ['Test document 1'], 'author': ['Richard Boulton']} If we add a field which is specified as a SORTABLE date which doesn't contain a valid date, an error will be raised when we try to process the date: >>> doc.fields.append(Field('date', 'An invalid date - this will generate an error when processed.')) >>> iconn.process(doc) Traceback (most recent call last): ... IndexerError: Value supplied to field 'date' must be a valid date: was 'An invalid date - this will generate an error when processed.': error is 'Unrecognised date format' If we add a field which is specified as a SORTABLE float which doesn't contain a valid floating point number, an error will be raised when we try to process the number: >>> doc.fields[-1] = Field('price', 'An invalid float - this will generate an error when processed.') >>> iconn.process(doc) Traceback (most recent call last): ... IndexerError: Value supplied to field 'price' must be a valid floating point number: was 'An invalid float - this will generate an error when processed.' We can access the Xapian document representation of the processed document to double check that this document has been indexed as we wanted: >>> xdoc = pdoc.prepare() >>> import cPickle >>> cPickle.loads(xdoc.get_data()) == pdoc.data True >>> [(term.term, term.wdf, [pos for pos in term.positer]) for term in xdoc.termlist()] [('1', 5, []), ('XA1', 5, []), ('XAdocument', 5, []), ('XAtest', 5, []), ('XB:Test document', 0, []), ('XCa', 1, [14]), ('XCbasic', 1, [15]), ('XCdocument', 2, [12, 17]), ('XCis', 1, [13]), ('XCtest', 1, [16]), ('XCthis', 1, [11]), ('ZXAdocument', 5, []), ('ZXAtest', 5, []), ('ZXCa', 1, []), ('ZXCbasic', 1, []), ('ZXCdocument', 2, []), ('ZXCis', 1, []), ('ZXCtest', 1, []), ('ZXCthis', 1, []), ('Za', 1, []), ('Zbasic', 1, []), ('Zdocument', 7, []), ('Zis', 1, []), ('Ztest', 6, []), ('Zthis', 1, []), ('a', 1, [14]), ('basic', 1, [15]), ('document', 7, [12, 17]), ('is', 1, [13]), ('test', 6, [16]), ('this', 1, [11])] >>> [(value.num, value.value) for value in xdoc.values()] [(0, 'Test document')] We can add terms directly to the processed document, specifying the wdf and position: >>> pdoc.add_term('text', 'newterm1', wdfinc=17, positions=200) >>> pdoc.add_term('text', 'newterm2', wdfinc=17, positions=(201, 202)) >>> [(term.term, term.wdf, [pos for pos in term.positer]) for term in xdoc.termlist()] [('1', 5, []), ('XA1', 5, []), ('XAdocument', 5, []), ('XAtest', 5, []), ('XB:Test document', 0, []), ('XCa', 1, [14]), ('XCbasic', 1, [15]), ('XCdocument', 2, [12, 17]), ('XCis', 1, [13]), ('XCnewterm1', 17, [200]), ('XCnewterm2', 17, [201, 202]), ('XCtest', 1, [16]), ('XCthis', 1, [11]), ('ZXAdocument', 5, []), ('ZXAtest', 5, []), ('ZXCa', 1, []), ('ZXCbasic', 1, []), ('ZXCdocument', 2, []), ('ZXCis', 1, []), ('ZXCtest', 1, []), ('ZXCthis', 1, []), ('Za', 1, []), ('Zbasic', 1, []), ('Zdocument', 7, []), ('Zis', 1, []), ('Ztest', 6, []), ('Zthis', 1, []), ('a', 1, [14]), ('basic', 1, [15]), ('document', 7, [12, 17]), ('is', 1, [13]), ('test', 6, [16]), ('this', 1, [11])] We can set the data directly too, as long as we set it to a dictionary: >>> pdoc.data = {'Empty': 'nothing'} >>> pdoc.data {'Empty': 'nothing'} >>> pdoc.data = None Traceback (most recent call last): ... TypeError: Cannot set data to any type other than a dict We can also get a representation of a processed document (though it only tells us the ID number): >>> pdoc xappy-0.5/xappy/marshall.py0000644000175000017500000000237510720056673015664 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""marshall.py: Marshal values into strings """ __docformat__ = "restructuredtext en" import math import xapian from replaylog import log as _log def float_to_string(value): """Marshall a floating point number to a string which sorts in the appropriate manner. """ return _log(xapian.sortable_serialise, value) def date_to_string(date): """Marshall a date to a string which sorts in the appropriate manner. """ return '%04d%02d%02d' % (date.year, date.month, date.day) xappy-0.5/xappy/marshall_doctest1.txt0000644000175000017500000000205310667526666017670 0ustar richardrichard >>> float_to_string(0) '\x80' >>> float_to_string(-0) '\x80' >>> float_to_string(2 ** -1023) '\x8f\xe4' >>> float_to_string(2 ** -1024) '\x8f\xe0' >>> float_to_string(2 ** -1074) '\x8f\x18' >>> float_to_string(2 ** -1075) '\x80' >>> float_to_string(-(2 ** -1024)) 'p\x1e' >>> float_to_string(-(2 ** -1023)) 'p\x1a' >>> float_to_string(-(2 ** -1074)) 'p\xe6' >>> float_to_string(-(2 ** -1075)) '\x80' Check that the values in test_vals sort in the right order. And then test with their negations. >>> pos_test_vals = (0, 2 ** -1075, 2 ** -1074, 2 ** -1023, 0.000001, 0.000002, 0.000005, 0.1, 0.2, 0.5, 1, 1.1, 1.8, 2, 1024.5, 2 ** 1022) >>> test_vals = [-val for val in pos_test_vals] >>> test_vals.reverse() >>> test_vals.extend(pos_test_vals) >>> prev_val = test_vals[0] >>> for val in test_vals: ... m_prev_val = float_to_string(prev_val) ... m_val = float_to_string(val) ... if val == prev_val: ... assert(m_val == m_prev_val) ... else: ... assert(val > prev_val) ... assert(m_val > m_prev_val) ... prev_val = val xappy-0.5/xappy/marshall_doctest2.txt0000644000175000017500000000112410667526666017667 0ustar richardrichard >>> import datetime, parsedate >>> date_to_string(datetime.date(1999, 12, 13)) '19991213' >>> test_date_inputs=['1066.11.05', '19700211', '19991213', '20070513'] >>> test_dates = [] >>> for date in test_date_inputs: ... test_dates.append(parsedate.date_from_string(date)) >>> prev_val = test_dates[0] >>> for val in test_dates: ... m_prev_val = date_to_string(prev_val) ... m_val = date_to_string(val) ... if val == prev_val: ... assert(m_val == m_prev_val) ... else: ... assert(val > prev_val) ... assert(m_val > m_prev_val) ... prev_val = val xappy-0.5/xappy/memutils.py0000644000175000017500000000521610711360156015707 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""memutils.py: Memory handling utilities. """ __docformat__ = "restructuredtext en" import os def _get_physical_mem_sysconf(): """Try getting a value for the physical memory using os.sysconf(). Returns None if no value can be obtained - otherwise, returns a value in bytes. """ if getattr(os, 'sysconf', None) is None: return None try: pagesize = os.sysconf('SC_PAGESIZE') except ValueError: try: pagesize = os.sysconf('SC_PAGE_SIZE') except ValueError: return None try: pagecount = os.sysconf('SC_PHYS_PAGES') except ValueError: return None return pagesize * pagecount def _get_physical_mem_win32(): """Try getting a value for the physical memory using GlobalMemoryStatus. This is a windows specific method. Returns None if no value can be obtained (eg, not running on windows) - otherwise, returns a value in bytes. """ try: import ctypes import ctypes.wintypes as wintypes except ValueError: return None class MEMORYSTATUS(wintypes.Structure): _fields_ = [ ('dwLength', wintypes.DWORD), ('dwMemoryLoad', wintypes.DWORD), ('dwTotalPhys', wintypes.DWORD), ('dwAvailPhys', wintypes.DWORD), ('dwTotalPageFile', wintypes.DWORD), ('dwAvailPageFile', wintypes.DWORD), ('dwTotalVirtual', wintypes.DWORD), ('dwAvailVirtual', wintypes.DWORD), ] m = MEMORYSTATUS() wintypes.windll.kernel32.GlobalMemoryStatus(wintypes.byref(m)) return m.dwTotalPhys def get_physical_memory(): """Get the amount of physical memory in the system, in bytes. If this can't be obtained, returns None. """ result = _get_physical_mem_sysconf() if result is not None: return result return _get_physical_mem_win32() xappy-0.5/xappy/parsedate.py0000644000175000017500000000341510667526666016043 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""parsedate.py: Parse date strings. """ __docformat__ = "restructuredtext en" import datetime import re yyyymmdd_re = re.compile(r'(?P[0-9]{4})(?P[0-9]{2})(?P[0-9]{2})$') yyyy_mm_dd_re = re.compile(r'(?P[0-9]{4})([-/.])(?P[0-9]{2})\2(?P[0-9]{2})$') def date_from_string(value): """Parse a string into a date. If the value supplied is already a date-like object (ie, has 'year', 'month' and 'day' attributes), it is returned without processing. Supported date formats are: - YYYYMMDD - YYYY-MM-DD - YYYY/MM/DD - YYYY.MM.DD """ if (hasattr(value, 'year') and hasattr(value, 'month') and hasattr(value, 'day')): return value mg = yyyymmdd_re.match(value) if mg is None: mg = yyyy_mm_dd_re.match(value) if mg is not None: year, month, day = (int(i) for i in mg.group('year', 'month', 'day')) return datetime.date(year, month, day) raise ValueError('Unrecognised date format') xappy-0.5/xappy/parsedate_doctest1.txt0000644000175000017500000000223210667526666020034 0ustar richardrichardGeneral tests of the datetime module. Dates may be supplied as YYYYMMDD: >>> date_from_string('19990201') datetime.date(1999, 2, 1) >>> date_from_string('19690201') datetime.date(1969, 2, 1) >>> date_from_string('20000228') datetime.date(2000, 2, 28) >>> date_from_string('20000229') datetime.date(2000, 2, 29) Dates may also be supplied as YYYY-MM-DD, YYYY/MM/DD or YYYY.MM.DD: >>> date_from_string('1999-02-01') datetime.date(1999, 2, 1) >>> date_from_string('1999/02/01') datetime.date(1999, 2, 1) >>> date_from_string('1999.02.01') datetime.date(1999, 2, 1) Out of range dates cause a ValueError: >>> date_from_string('19000229') Traceback (most recent call last): ... ValueError: day is out of range for month >>> date_from_string('20000001') Traceback (most recent call last): ... ValueError: month must be in 1..12 If we pass a datetime.date object (or something which looks similar) it is returned unchanged: >>> date_from_string(datetime.date(2001, 7, 11)) datetime.date(2001, 7, 11) If we pass something unrecognisible, we get a ValueError: >>> date_from_string('hello world') Traceback (most recent call last): ... ValueError: Unrecognised date format xappy-0.5/xappy/replaylog.py0000644000175000017500000003121610720056673016053 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""replaylog.py: Log all xapian calls to a file, so that they can be replayed. """ __docformat__ = "restructuredtext en" import datetime import sys import thread import threading import time import traceback import types import weakref import xapian from pprint import pprint # The logger in use. _replay_log = None # True if a replay log has ever been in use since import time. _had_replay_log = False class NotifyingDeleteObject(object): """An wrapping for an object which calls a callback when its deleted. Note that the callback will be called from a __del__ method, so shouldn't raise any exceptions, and probably shouldn't make new references to the object supplied to it. """ def __init__(self, obj, callback): self.obj = obj self.callback = callback def __del__(self): self.callback(self.obj) class ReplayLog(object): """Log of xapian calls, to be replayed. """ def __init__(self, logpath): """Create a new replay log. """ # Mutex used to protect all access to _fd self._fd_mutex = threading.Lock() self._fd = file(logpath, 'wb') # Mutex used to protect all access to members other than _fd self._mutex = threading.Lock() self._next_call = 1 self._next_thread = 0 self._thread_ids = {} self._objs = weakref.WeakKeyDictionary() self._next_num = 1 self._xapian_classes = {} self._xapian_functions = {} self._xapian_methods = {} for name in dir(xapian): item = getattr(xapian, name) has_members = False for membername in dir(item): member = getattr(item, membername) if isinstance(member, types.MethodType): self._xapian_methods[member.im_func] = (name, membername) has_members = True if has_members: self._xapian_classes[item] = name if isinstance(item, types.BuiltinFunctionType): self._xapian_functions[item] = name def _get_obj_num(self, obj, maybe_new): """Get the number associated with an object. If maybe_new is False, a value of 0 will be supplied if the object hasn't already been seen. Otherwise, a new (and previously unused) value will be allocated to the object. The mutex should be held when this is called. """ try: num = self._objs[obj] return num.obj except KeyError: pass if not maybe_new: return 0 self._objs[obj] = NotifyingDeleteObject(self._next_num, self._obj_gone) self._next_num += 1 return self._next_num - 1 def _is_xap_obj(self, obj): """Return True iff an object is an instance of a xapian object. (Also returns true if the object is an instance of a subclass of a xapian object.) The mutex should be held when this is called. """ # Check for xapian classes. classname = self._xapian_classes.get(type(obj), None) if classname is not None: return True # Check for subclasses of xapian classes. for classobj, classname in self._xapian_classes.iteritems(): if isinstance(obj, classobj): return True # Not a xapian class or subclass. return False def _get_xap_name(self, obj, maybe_new=False): """Get the name of a xapian class or method. The mutex should be held when this is called. """ # Check if it's a xapian class, or subclass. if isinstance(obj, types.TypeType): classname = self._xapian_classes.get(obj, None) if classname is not None: return classname for classobj, classname in self._xapian_classes.iteritems(): if issubclass(obj, classobj): return "subclassof_%s" % (classname, ) return None # Check if it's a xapian function. if isinstance(obj, types.BuiltinFunctionType): funcname = self._xapian_functions.get(obj, None) if funcname is not None: return funcname # Check if it's a proxied object. if isinstance(obj, LoggedProxy): classname = self._xapian_classes.get(obj.__class__, None) if classname is not None: objnum = self._get_obj_num(obj, maybe_new=maybe_new) return "%s#%d" % (classname, objnum) # Check if it's a proxied method. if isinstance(obj, LoggedProxyMethod): classname, methodname = self._xapian_methods[obj.real.im_func] objnum = self._get_obj_num(obj.proxyobj, maybe_new=maybe_new) return "%s#%d.%s" % (classname, objnum, methodname) # Check if it's a subclass of a xapian class. Note: this will only # pick up subclasses, because the original classes are filtered out # higher up. for classobj, classname in self._xapian_classes.iteritems(): if isinstance(obj, classobj): objnum = self._get_obj_num(obj, maybe_new=maybe_new) return "subclassof_%s#%d" % (classname, objnum) return None def _log(self, msg): self._fd_mutex.acquire() try: # msg = '%s,%s' % ( # datetime.datetime.fromtimestamp(time.time()).isoformat(), # msg, # ) self._fd.write(msg) self._fd.flush() finally: self._fd_mutex.release() def _repr_arg(self, arg): """Return a representation of an argument. The mutex should be held when this is called. """ xapargname = self._get_xap_name(arg) if xapargname is not None: return xapargname if isinstance(arg, basestring): if isinstance(arg, unicode): arg = arg.encode('utf-8') return 'str(%d,%s)' % (len(arg), arg) if isinstance(arg, long): try: arg = int(arg) except OverFlowError: pass if isinstance(arg, long): return 'long(%d)' % arg if isinstance(arg, int): return 'int(%d)' % arg if isinstance(arg, float): return 'float(%f)' % arg if arg is None: return 'None' if hasattr(arg, '__iter__'): seq = [] for item in arg: seq.append(self._repr_arg(item)) return 'list(%s)' % ','.join(seq) return 'UNKNOWN:' + str(arg) def _repr_args(self, args): """Return a representation of a list of arguments. The mutex should be held when this is called. """ logargs = [] for arg in args: logargs.append(self._repr_arg(arg)) return ','.join(logargs) def _get_call_id(self): """Get an ID string for a call. The mutex should be held when this is called. """ call_num = self._next_call self._next_call += 1 thread_id = thread.get_ident() try: thread_num = self._thread_ids[thread_id] except KeyError: thread_num = self._next_thread self._thread_ids[thread_id] = thread_num self._next_thread += 1 if thread_num is 0: return "%s" % call_num return "%dT%d" % (call_num, thread_num) def log_call(self, call, *args): """Add a log message about a call. Returns a number for the call, so it can be tied to a particular result. """ self._mutex.acquire() try: logargs = self._repr_args(args) xapobjname = self._get_xap_name(call) call_id = self._get_call_id() finally: self._mutex.release() if xapobjname is not None: self._log("CALL%s:%s(%s)\n" % (call_id, xapobjname, logargs)) else: self._log("CALL%s:UNKNOWN:%r(%s)\n" % (call_id, call, logargs)) return call_id def log_except(self, (etype, value, tb), call_id): """Log an exception which has occurred. """ # No access to an members, so no need to acquire mutex. exc = traceback.format_exception_only(etype, value) self._log("EXCEPT%s:%s\n" % (call_id, ''.join(exc).strip())) def log_retval(self, ret, call_id): """Log a return value. """ if ret is None: self._log("RET%s:None\n" % call_id) return self._mutex.acquire() try: # If it's a xapian object, return a proxy for it. if self._is_xap_obj(ret): ret = LoggedProxy(ret) xapobjname = self._get_xap_name(ret, maybe_new=True) msg = "RET%s:%s\n" % (call_id, self._repr_arg(ret)) finally: self._mutex.release() # Not a xapian object - just return it. self._log(msg) return ret def _obj_gone(self, num): """Log that an object has been deleted. """ self._log('DEL:#%d\n' % num) class LoggedProxy(object): """A proxy for a xapian object, which logs all calls made on the object. """ def __init__(self, obj): self.__obj = obj def __getattribute__(self, name): obj = object.__getattribute__(self, '_LoggedProxy__obj') if name == '__obj': return obj real = getattr(obj, name) if not isinstance(real, types.MethodType): return real return LoggedProxyMethod(real, self) def __iter__(self): obj = object.__getattribute__(self, '_LoggedProxy__obj') return obj.__iter__() def __len__(self): obj = object.__getattribute__(self, '_LoggedProxy__obj') return obj.__len__() def __repr__(self): obj = object.__getattribute__(self, '_LoggedProxy__obj') return '' % obj.__repr__() def __str__(self): obj = object.__getattribute__(self, '_LoggedProxy__obj') return obj.__str__() class LoggedProxyMethod(object): """A proxy for a xapian method, which logs all calls made on the method. """ def __init__(self, real, proxyobj): """Make a proxy for the method. """ self.real = real self.proxyobj = proxyobj def __call__(self, *args): """Call the proxied method, logging the call. """ return log(self, *args) def set_replay_path(logpath): """Set the path for the replay log. """ global _replay_log global _had_replay_log if logpath is None: _replay_log = None else: _had_replay_log = True _replay_log = ReplayLog(logpath) def _unproxy_call_and_args(call, args): """Convert a call and list of arguments to unproxied form. """ if isinstance(call, LoggedProxyMethod): realcall = call.real else: realcall = call realargs = [] for arg in args: if isinstance(arg, LoggedProxy): arg = arg.__obj realargs.append(arg) return realcall, realargs def log(call, *args): """Make a call to xapian, and log it. """ # If we've never had a replay log in force, no need to unproxy objects. global _had_replay_log if not _had_replay_log: return call(*args) # Get unproxied versions of the call and arguments. realcall, realargs = _unproxy_call_and_args(call, args) # If we have no replay log currently, just do the call. global _replay_log replay_log = _replay_log if replay_log is None: return realcall(*realargs) # We have a replay log: do a logged version of the call. call_id = replay_log.log_call(call, *args) try: ret = realcall(*realargs) except: replay_log.log_except(sys.exc_info(), call_id) raise return replay_log.log_retval(ret, call_id) #set_replay_path('replay.log') xappy-0.5/xappy/schema.py0000644000175000017500000000215110772230325015304 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2008 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""schema.py: xdefinitions and implementations of field actions. """ __docformat__ = "restructuredtext en" import errors as _errors from replaylog import log as _log import parsedate as _parsedate class Schema(object): def __init__(self): pass if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/xappy/searchconnection.py0000644000175000017500000022740711005457603017406 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""searchconnection.py: A connection to the search engine for searching. """ __docformat__ = "restructuredtext en" import _checkxapian import os as _os import cPickle as _cPickle import math import xapian as _xapian from datastructures import * from fieldactions import * import fieldmappings as _fieldmappings import highlight as _highlight import errors as _errors import indexerconnection as _indexerconnection import re as _re from replaylog import log as _log class SearchResult(ProcessedDocument): """A result from a search. As well as being a ProcessedDocument representing the document in the database, the result has several members which may be used to get information about how well the document matches the search: - `rank`: The rank of the document in the search results, starting at 0 (ie, 0 is the "top" result, 1 is the second result, etc). - `weight`: A floating point number indicating the weight of the result document. The value is only meaningful relative to other results for a given search - a different search, or the same search with a different database, may give an entirely different scale to the weights. This should not usually be displayed to users, but may be useful if trying to perform advanced reweighting operations on search results. - `percent`: A percentage value for the weight of a document. This is just a rescaled form of the `weight` member. It doesn't represent any kind of probability value; the only real meaning of the numbers is that, within a single set of results, a document with a higher percentage corresponds to a better match. Because the percentage doesn't really represent a probability, or a confidence value, it is probably unhelpful to display it to most users, since they tend to place an over emphasis on its meaning. However, it is included because it may be useful occasionally. """ def __init__(self, msetitem, results): ProcessedDocument.__init__(self, results._fieldmappings, msetitem.document) self.rank = msetitem.rank self.weight = msetitem.weight self.percent = msetitem.percent self._results = results def _get_language(self, field): """Get the language that should be used for a given field. Raises a KeyError if the field is not known. """ actions = self._results._conn._field_actions[field]._actions for action, kwargslist in actions.iteritems(): if action == FieldActions.INDEX_FREETEXT: for kwargs in kwargslist: try: return kwargs['language'] except KeyError: pass return 'none' def summarise(self, field, maxlen=600, hl=('', ''), query=None): """Return a summarised version of the field specified. This will return a summary of the contents of the field stored in the search result, with words which match the query highlighted. The maximum length of the summary (in characters) may be set using the maxlen parameter. The return value will be a string holding the summary, with highlighting applied. If there are multiple instances of the field in the document, the instances will be joined with a newline character. To turn off highlighting, set hl to None. Each highlight will consist of the first entry in the `hl` list being placed before the word, and the second entry in the `hl` list being placed after the word. Any XML or HTML style markup tags in the field will be stripped before the summarisation algorithm is applied. If `query` is supplied, it should contain a Query object, as returned from SearchConnection.query_parse() or related methods, which will be used as the basis of the summarisation and highlighting rather than the query which was used for the search. Raises KeyError if the field is not known. """ highlighter = _highlight.Highlighter(language_code=self._get_language(field)) field = self.data[field] results = [] text = '\n'.join(field) if query is None: query = self._results._query return highlighter.makeSample(text, query, maxlen, hl) def highlight(self, field, hl=('', ''), strip_tags=False, query=None): """Return a highlighted version of the field specified. This will return all the contents of the field stored in the search result, with words which match the query highlighted. The return value will be a list of strings (corresponding to the list of strings which is the raw field data). Each highlight will consist of the first entry in the `hl` list being placed before the word, and the second entry in the `hl` list being placed after the word. If `strip_tags` is True, any XML or HTML style markup tags in the field will be stripped before highlighting is applied. If `query` is supplied, it should contain a Query object, as returned from SearchConnection.query_parse() or related methods, which will be used as the basis of the summarisation and highlighting rather than the query which was used for the search. Raises KeyError if the field is not known. """ highlighter = _highlight.Highlighter(language_code=self._get_language(field)) field = self.data[field] results = [] if query is None: query = self._results._query for text in field: results.append(highlighter.highlight(text, query, hl, strip_tags)) return results def __repr__(self): return ('' % (self.rank, self.id, self.data)) class SearchResultIter(object): """An iterator over a set of results from a search. """ def __init__(self, results, order): self._results = results self._order = order if self._order is None: self._iter = iter(results._mset) else: self._iter = iter(self._order) def next(self): if self._order is None: msetitem = self._iter.next() else: index = self._iter.next() msetitem = self._results._mset.get_hit(index) return SearchResult(msetitem, self._results) def _get_significant_digits(value, lower, upper): """Get the significant digits of value which are constrained by the (inclusive) lower and upper bounds. If there are no significant digits which are definitely within the bounds, exactly one significant digit will be returned in the result. >>> _get_significant_digits(15,15,15) 15 >>> _get_significant_digits(15,15,17) 20 >>> _get_significant_digits(4777,208,6000) 5000 >>> _get_significant_digits(4777,4755,4790) 4800 >>> _get_significant_digits(4707,4695,4710) 4700 >>> _get_significant_digits(4719,4717,4727) 4720 >>> _get_significant_digits(0,0,0) 0 >>> _get_significant_digits(9,9,10) 9 >>> _get_significant_digits(9,9,100) 9 """ assert(lower <= value) assert(value <= upper) diff = upper - lower # Get the first power of 10 greater than the difference. # This corresponds to the magnitude of the smallest significant digit. if diff == 0: pos_pow_10 = 1 else: pos_pow_10 = int(10 ** math.ceil(math.log10(diff))) # Special case for situation where we don't have any significant digits: # get the magnitude of the most significant digit in value. if pos_pow_10 > value: if value == 0: pos_pow_10 = 1 else: pos_pow_10 = int(10 ** math.floor(math.log10(value))) # Return the value, rounded to the nearest multiple of pos_pow_10 return ((value + pos_pow_10 // 2) // pos_pow_10) * pos_pow_10 class SearchResults(object): """A set of results of a search. """ def __init__(self, conn, enq, query, mset, fieldmappings, tagspy, tagfields, facetspy, facetfields, facethierarchy, facetassocs): self._conn = conn self._enq = enq self._query = query self._mset = mset self._mset_order = None self._fieldmappings = fieldmappings self._tagspy = tagspy if tagfields is None: self._tagfields = None else: self._tagfields = set(tagfields) self._facetspy = facetspy self._facetfields = facetfields self._facethierarchy = facethierarchy self._facetassocs = facetassocs self._numeric_ranges_built = {} def _cluster(self, num_clusters, maxdocs, fields=None): """Cluster results based on similarity. Note: this method is experimental, and will probably disappear or change in the future. The number of clusters is specified by num_clusters: unless there are too few results, there will be exaclty this number of clusters in the result. """ clusterer = _xapian.ClusterSingleLink() xapclusters = _xapian.ClusterAssignments() docsim = _xapian.DocSimCosine() source = _xapian.MSetDocumentSource(self._mset, maxdocs) if fields is None: clusterer.cluster(self._conn._index, xapclusters, docsim, source, num_clusters) else: decider = self._make_expand_decider(fields) clusterer.cluster(self._conn._index, xapclusters, docsim, source, decider, num_clusters) newid = 0 idmap = {} clusters = {} for item in self._mset: docid = item.docid clusterid = xapclusters.cluster(docid) if clusterid not in idmap: idmap[clusterid] = newid newid += 1 clusterid = idmap[clusterid] if clusterid not in clusters: clusters[clusterid] = [] clusters[clusterid].append(item.rank) return clusters def _reorder_by_clusters(self, clusters): """Reorder the mset based on some clusters. """ if self.startrank != 0: raise _errors.SearchError("startrank must be zero to reorder by clusters") reordered = False tophits = [] nottophits = [] clusterstarts = dict(((c[0], None) for c in clusters.itervalues())) for i in xrange(self.endrank): if i in clusterstarts: tophits.append(i) else: nottophits.append(i) self._mset_order = tophits self._mset_order.extend(nottophits) def _make_expand_decider(self, fields): """Make an expand decider which accepts only terms in the specified field. """ prefixes = {} if isinstance(fields, basestring): fields = [fields] for field in fields: try: actions = self._conn._field_actions[field]._actions except KeyError: continue for action, kwargslist in actions.iteritems(): if action == FieldActions.INDEX_FREETEXT: prefix = self._conn._field_mappings.get_prefix(field) prefixes[prefix] = None prefixes['Z' + prefix] = None if action in (FieldActions.INDEX_EXACT, FieldActions.TAG, FieldActions.FACET,): prefix = self._conn._field_mappings.get_prefix(field) prefixes[prefix] = None prefix_re = _re.compile('|'.join([_re.escape(x) + '[^A-Z]' for x in prefixes.keys()])) class decider(_xapian.ExpandDecider): def __call__(self, term): return prefix_re.match(term) is not None return decider() def _reorder_by_similarity(self, count, maxcount, max_similarity, fields=None): """Reorder results based on similarity. The top `count` documents will be chosen such that they are relatively dissimilar. `maxcount` documents will be considered for moving around, and `max_similarity` is a value between 0 and 1 indicating the maximum similarity to the previous document before a document is moved down the result set. Note: this method is experimental, and will probably disappear or change in the future. """ if self.startrank != 0: raise _errors.SearchError("startrank must be zero to reorder by similiarity") ds = _xapian.DocSimCosine() ds.set_termfreqsource(_xapian.DatabaseTermFreqSource(self._conn._index)) if fields is not None: ds.set_expand_decider(self._make_expand_decider(fields)) tophits = [] nottophits = [] full = False reordered = False sim_count = 0 new_order = [] end = min(self.endrank, maxcount) for i in xrange(end): if full: new_order.append(i) continue hit = self._mset.get_hit(i) if len(tophits) == 0: tophits.append(hit) continue # Compare each incoming hit to tophits maxsim = 0.0 for tophit in tophits[-1:]: sim_count += 1 sim = ds.similarity(hit.document, tophit.document) if sim > maxsim: maxsim = sim # If it's not similar to an existing hit, add to tophits. if maxsim < max_similarity: tophits.append(hit) else: nottophits.append(hit) reordered = True # If we're full of hits, append to the end. if len(tophits) >= count: for hit in tophits: new_order.append(hit.rank) for hit in nottophits: new_order.append(hit.rank) full = True if not full: for hit in tophits: new_order.append(hit.rank) for hit in nottophits: new_order.append(hit.rank) if end != self.endrank: new_order.extend(range(end, self.endrank)) assert len(new_order) == self.endrank if reordered: self._mset_order = new_order else: assert new_order == range(self.endrank) def __repr__(self): return ("" % ( self.startrank, self.endrank, self.more_matches, self.matches_lower_bound, self.matches_upper_bound, self.matches_estimated, self.estimate_is_exact, )) def _get_more_matches(self): # This check relies on us having asked for at least one more result # than retrieved to be checked. return (self.matches_lower_bound > self.endrank) more_matches = property(_get_more_matches, doc= """Check whether there are further matches after those in this result set. """) def _get_startrank(self): return self._mset.get_firstitem() startrank = property(_get_startrank, doc= """Get the rank of the first item in the search results. This corresponds to the "startrank" parameter passed to the search() method. """) def _get_endrank(self): return self._mset.get_firstitem() + len(self._mset) endrank = property(_get_endrank, doc= """Get the rank of the item after the end of the search results. If there are sufficient results in the index, this corresponds to the "endrank" parameter passed to the search() method. """) def _get_lower_bound(self): return self._mset.get_matches_lower_bound() matches_lower_bound = property(_get_lower_bound, doc= """Get a lower bound on the total number of matching documents. """) def _get_upper_bound(self): return self._mset.get_matches_upper_bound() matches_upper_bound = property(_get_upper_bound, doc= """Get an upper bound on the total number of matching documents. """) def _get_human_readable_estimate(self): lower = self._mset.get_matches_lower_bound() upper = self._mset.get_matches_upper_bound() est = self._mset.get_matches_estimated() return _get_significant_digits(est, lower, upper) matches_human_readable_estimate = property(_get_human_readable_estimate, doc= """Get a human readable estimate of the number of matching documents. This consists of the value returned by the "matches_estimated" property, rounded to an appropriate number of significant digits (as determined by the values of the "matches_lower_bound" and "matches_upper_bound" properties). """) def _get_estimated(self): return self._mset.get_matches_estimated() matches_estimated = property(_get_estimated, doc= """Get an estimate for the total number of matching documents. """) def _estimate_is_exact(self): return self._mset.get_matches_lower_bound() == \ self._mset.get_matches_upper_bound() estimate_is_exact = property(_estimate_is_exact, doc= """Check whether the estimated number of matching documents is exact. If this returns true, the estimate given by the `matches_estimated` property is guaranteed to be correct. If this returns false, it is possible that the actual number of matching documents is different from the number given by the `matches_estimated` property. """) def get_hit(self, index): """Get the hit with a given index. """ if self._mset_order is None: msetitem = self._mset.get_hit(index) else: msetitem = self._mset.get_hit(self._mset_order[index]) return SearchResult(msetitem, self) __getitem__ = get_hit def __iter__(self): """Get an iterator over the hits in the search result. The iterator returns the results in increasing order of rank. """ return SearchResultIter(self, self._mset_order) def __len__(self): """Get the number of hits in the search result. Note that this is not (usually) the number of matching documents for the search. If startrank is non-zero, it's not even the rank of the last document in the search result. It's simply the number of hits stored in the search result. It is, however, the number of items returned by the iterator produced by calling iter() on this SearchResults object. """ return len(self._mset) def get_top_tags(self, field, maxtags): """Get the most frequent tags in a given field. - `field` - the field to get tags for. This must have been specified in the "gettags" argument of the search() call. - `maxtags` - the maximum number of tags to return. Returns a sequence of 2-item tuples, in which the first item in the tuple is the tag, and the second is the frequency of the tag in the matches seen (as an integer). """ if 'tags' in _checkxapian.missing_features: raise errors.SearchError("Tags unsupported with this release of xapian") if self._tagspy is None or field not in self._tagfields: raise _errors.SearchError("Field %r was not specified for getting tags" % field) prefix = self._conn._field_mappings.get_prefix(field) return self._tagspy.get_top_terms(prefix, maxtags) def get_suggested_facets(self, maxfacets=5, desired_num_of_categories=7, required_facets=None): """Get a suggested set of facets, to present to the user. This returns a list, in descending order of the usefulness of the facet, in which each item is a tuple holding: - fieldname of facet. - sequence of 2-tuples holding the suggested values or ranges for that field: For facets of type 'string', the first item in the 2-tuple will simply be the string supplied when the facet value was added to its document. For facets of type 'float', it will be a 2-tuple, holding floats giving the start and end of the suggested value range. The second item in the 2-tuple will be the frequency of the facet value or range in the result set. If required_facets is not None, it must be a field name, or a sequence of field names. Any field names mentioned in required_facets will be returned if there are any facet values at all in the search results for that field. The facet will only be omitted if there are no facet values at all for the field. The value of maxfacets will be respected as far as possible; the exception is that if there are too many fields listed in required_facets with at least one value in the search results, extra facets will be returned (ie, obeying the required_facets parameter is considered more important than the maxfacets parameter). If facet_hierarchy was indicated when search() was called, and the query included facets, then only subfacets of those query facets and top-level facets will be included in the returned list. Furthermore top-level facets will only be returned if there are remaining places in the list after it has been filled with subfacets. Note that required_facets is still respected regardless of the facet hierarchy. If a query type was specified when search() was called, and the query included facets, then facets with an association of Never to the query type are never returned, even if mentioned in required_facets. Facets with an association of Preferred are listed before others in the returned list. """ if 'facets' in _checkxapian.missing_features: raise errors.SearchError("Facets unsupported with this release of xapian") if self._facetspy is None: raise _errors.SearchError("Facet selection wasn't enabled when the search was run") if isinstance(required_facets, basestring): required_facets = [required_facets] scores = [] facettypes = {} for field, slot, kwargslist in self._facetfields: type = None for kwargs in kwargslist: type = kwargs.get('type', None) if type is not None: break if type is None: type = 'string' if type == 'float': if field not in self._numeric_ranges_built: self._facetspy.build_numeric_ranges(slot, desired_num_of_categories) self._numeric_ranges_built[field] = None facettypes[field] = type score = self._facetspy.score_categorisation(slot, desired_num_of_categories) scores.append((score, field, slot)) # Sort on whether facet is top-level ahead of score (use subfacets first), # and on whether facet is preferred for the query type ahead of anything else if self._facethierarchy: # Note, tuple[-2] is the value of 'field' in a scores tuple scores = [(tuple[-2] not in self._facethierarchy,) + tuple for tuple in scores] if self._facetassocs: preferred = _indexerconnection.IndexerConnection.FacetQueryType_Preferred scores = [(self._facetassocs.get(tuple[-2]) != preferred,) + tuple for tuple in scores] scores.sort() if self._facethierarchy: index = 1 else: index = 0 if self._facetassocs: index += 1 if index > 0: scores = [tuple[index:] for tuple in scores] results = [] required_results = [] for score, field, slot in scores: # Check if the facet is required required = False if required_facets is not None: required = field in required_facets # If we've got enough facets, and the field isn't required, skip it if not required and len(results) + len(required_results) >= maxfacets: continue # Get the values values = self._facetspy.get_values_as_dict(slot) if field in self._numeric_ranges_built: if '' in values: del values[''] # Required facets must occur at least once, other facets must occur # at least twice. if required: if len(values) < 1: continue else: if len(values) <= 1: continue newvalues = [] if facettypes[field] == 'float': # Convert numbers to python numbers, and number ranges to a # python tuple of two numbers. for value, frequency in values.iteritems(): if len(value) <= 9: value1 = _log(_xapian.sortable_unserialise, value) value2 = value1 else: value1 = _log(_xapian.sortable_unserialise, value[:9]) value2 = _log(_xapian.sortable_unserialise, value[9:]) newvalues.append(((value1, value2), frequency)) else: for value, frequency in values.iteritems(): newvalues.append((value, frequency)) newvalues.sort() if required: required_results.append((score, field, newvalues)) else: results.append((score, field, newvalues)) # Throw away any excess results if we have more required_results to # insert. maxfacets = maxfacets - len(required_results) if maxfacets <= 0: results = required_results else: results = results[:maxfacets] results.extend(required_results) results.sort() # Throw away the scores because they're not meaningful outside this # algorithm. results = [(field, newvalues) for (score, field, newvalues) in results] return results class SearchConnection(object): """A connection to the search engine for searching. The connection will access a view of the database. """ _qp_flags_base = _xapian.QueryParser.FLAG_LOVEHATE _qp_flags_phrase = _xapian.QueryParser.FLAG_PHRASE _qp_flags_synonym = (_xapian.QueryParser.FLAG_AUTO_SYNONYMS | _xapian.QueryParser.FLAG_AUTO_MULTIWORD_SYNONYMS) _qp_flags_bool = _xapian.QueryParser.FLAG_BOOLEAN _index = None def __init__(self, indexpath): """Create a new connection to the index for searching. There may only an arbitrary number of search connections for a particular database open at a given time (regardless of whether there is a connection for indexing open as well). If the database doesn't exist, an exception will be raised. """ self._index = _log(_xapian.Database, indexpath) self._indexpath = indexpath # Read the actions. self._load_config() self._close_handlers = [] def __del__(self): self.close() def append_close_handler(self, handler, userdata=None): """Append a callback to the list of close handlers. These will be called when the SearchConnection is closed. This happens when the close() method is called, or when the SearchConnection object is deleted. The callback will be passed two arguments: the path to the SearchConnection object, and the userdata supplied to this method. The handlers will be called in the order in which they were added. The handlers will be called after the connection has been closed, so cannot prevent it closing: their return value will be ignored. In addition, they should not raise any exceptions. """ self._close_handlers.append((handler, userdata)) def _get_sort_type(self, field): """Get the sort type that should be used for a given field. """ try: actions = self._field_actions[field]._actions except KeyError: actions = {} for action, kwargslist in actions.iteritems(): if action == FieldActions.SORT_AND_COLLAPSE: for kwargs in kwargslist: return kwargs['type'] def _load_config(self): """Load the configuration for the database. """ # Note: this code is basically duplicated in the IndexerConnection # class. Move it to a shared location. assert self._index is not None config_str = _log(self._index.get_metadata, '_xappy_config') if len(config_str) == 0: self._field_actions = {} self._field_mappings = _fieldmappings.FieldMappings() self._facet_hierarchy = {} self._facet_query_table = {} return try: (self._field_actions, mappings, self._facet_hierarchy, self._facet_query_table, self._next_docid) = _cPickle.loads(config_str) except ValueError: # Backwards compatibility - configuration used to lack _facet_hierarchy and _facet_query_table (self._field_actions, mappings, self._next_docid) = _cPickle.loads(config_str) self._facet_hierarchy = {} self._facet_query_table = {} self._field_mappings = _fieldmappings.FieldMappings(mappings) def reopen(self): """Reopen the connection. This updates the revision of the index which the connection references to the latest flushed revision. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") self._index.reopen() # Re-read the actions. self._load_config() def close(self): """Close the connection to the database. It is important to call this method before allowing the class to be garbage collected to ensure that the connection is cleaned up promptly. No other methods may be called on the connection after this has been called. (It is permissible to call close() multiple times, but only the first call will have any effect.) If an exception occurs, the database will be closed, but changes since the last call to flush may be lost. """ if self._index is None: return # Remember the index path indexpath = self._indexpath # There is currently no "close()" method for xapian databases, so # we have to rely on the garbage collector. Since we never copy # the _index property out of this class, there should be no cycles, # so the standard python implementation should garbage collect # _index straight away. A close() method is planned to be added to # xapian at some point - when it is, we should call it here to make # the code more robust. self._index = None self._indexpath = None self._field_actions = None self._field_mappings = None # Call the close handlers. for handler, userdata in self._close_handlers: try: handler(indexpath, userdata) except Exception, e: import sys, traceback print >>sys.stderr, "WARNING: unhandled exception in handler called by SearchConnection.close(): %s" % traceback.format_exception_only(type(e), e) def get_doccount(self): """Count the number of documents in the database. This count will include documents which have been added or removed but not yet flushed(). """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") return self._index.get_doccount() OP_AND = _xapian.Query.OP_AND OP_OR = _xapian.Query.OP_OR def query_composite(self, operator, queries): """Build a composite query from a list of queries. The queries are combined with the supplied operator, which is either SearchConnection.OP_AND or SearchConnection.OP_OR. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") return _log(_xapian.Query, operator, list(queries)) def query_multweight(self, query, multiplier): """Build a query which modifies the weights of a subquery. This produces a query which returns the same documents as the subquery, and in the same order, but with the weights assigned to each document multiplied by the value of "multiplier". "multiplier" may be any floating point value, but negative values will be clipped to 0, since Xapian doesn't support negative weights. This can be useful when producing queries to be combined with query_composite, because it allows the relative importance of parts of the query to be adjusted. """ return _log(_xapian.Query, _xapian.Query.OP_SCALE_WEIGHT, query, multiplier) def query_filter(self, query, filter, exclude=False): """Filter a query with another query. If exclude is False (or not specified), documents will only match the resulting query if they match the both the first and second query: the results of the first query are "filtered" to only include those which also match the second query. If exclude is True, documents will only match the resulting query if they match the first query, but not the second query: the results of the first query are "filtered" to only include those which do not match the second query. Documents will always be weighted according to only the first query. - `query`: The query to filter. - `filter`: The filter to apply to the query. - `exclude`: If True, the sense of the filter is reversed - only documents which do not match the second query will be returned. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") if not isinstance(filter, _xapian.Query): raise _errors.SearchError("Filter must be a Xapian Query object") if exclude: return _log(_xapian.Query, _xapian.Query.OP_AND_NOT, query, filter) else: return _log(_xapian.Query, _xapian.Query.OP_FILTER, query, filter) def query_adjust(self, primary, secondary): """Adjust the weights of one query with a secondary query. Documents will be returned from the resulting query if and only if they match the primary query (specified by the "primary" parameter). However, the weights (and hence, the relevance rankings) of the documents will be adjusted by adding weights from the secondary query (specified by the "secondary" parameter). """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") return _log(_xapian.Query, _xapian.Query.OP_AND_MAYBE, primary, secondary) def query_range(self, field, begin, end): """Create a query for a range search. This creates a query which matches only those documents which have a field value in the specified range. Begin and end must be appropriate values for the field, according to the 'type' parameter supplied to the SORTABLE action for the field. The begin and end values are both inclusive - any documents with a value equal to begin or end will be returned (unless end is less than begin, in which case no documents will be returned). Begin or end may be set to None in order to create an open-ended range. (They may also both be set to None, which will generate a query which matches all documents containing any value for the field.) """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") if begin is None and end is None: # Return a "match everything" query return _log(_xapian.Query, '') try: slot = self._field_mappings.get_slot(field, 'collsort') except KeyError: # Return a "match nothing" query return _log(_xapian.Query) sorttype = self._get_sort_type(field) marshaller = SortableMarshaller(False) fn = marshaller.get_marshall_function(field, sorttype) if begin is not None: begin = fn(field, begin) if end is not None: end = fn(field, end) if begin is None: return _log(_xapian.Query, _xapian.Query.OP_VALUE_LE, slot, end) if end is None: return _log(_xapian.Query, _xapian.Query.OP_VALUE_GE, slot, begin) return _log(_xapian.Query, _xapian.Query.OP_VALUE_RANGE, slot, begin, end) def query_facet(self, field, val): """Create a query for a facet value. This creates a query which matches only those documents which have a facet value in the specified range. For a numeric range facet, val should be a tuple holding the start and end of the range, or a comma separated string holding two floating point values. For other facets, val should be the value to look for. The start and end values are both inclusive - any documents with a value equal to start or end will be returned (unless end is less than start, in which case no documents will be returned). """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") if 'facets' in _checkxapian.missing_features: raise errors.SearchError("Facets unsupported with this release of xapian") try: actions = self._field_actions[field]._actions except KeyError: actions = {} facettype = None for action, kwargslist in actions.iteritems(): if action == FieldActions.FACET: for kwargs in kwargslist: facettype = kwargs.get('type', None) if facettype is not None: break if facettype is not None: break if facettype == 'float': if isinstance(val, basestring): val = [float(v) for v in val.split(',', 2)] assert(len(val) == 2) try: slot = self._field_mappings.get_slot(field, 'facet') except KeyError: return _log(_xapian.Query) # FIXME - check that sorttype == self._get_sort_type(field) sorttype = 'float' marshaller = SortableMarshaller(False) fn = marshaller.get_marshall_function(field, sorttype) begin = fn(field, val[0]) end = fn(field, val[1]) return _log(_xapian.Query, _xapian.Query.OP_VALUE_RANGE, slot, begin, end) else: assert(facettype == 'string' or facettype is None) prefix = self._field_mappings.get_prefix(field) return _log(_xapian.Query, prefix + val.lower()) def _prepare_queryparser(self, allow, deny, default_op, default_allow, default_deny): """Prepare (and return) a query parser using the specified fields and operator. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") if isinstance(allow, basestring): allow = (allow, ) if isinstance(deny, basestring): deny = (deny, ) if allow is not None and len(allow) == 0: allow = None if deny is not None and len(deny) == 0: deny = None if allow is not None and deny is not None: raise _errors.SearchError("Cannot specify both `allow` and `deny` " "(got %r and %r)" % (allow, deny)) if isinstance(default_allow, basestring): default_allow = (default_allow, ) if isinstance(default_deny, basestring): default_deny = (default_deny, ) if default_allow is not None and len(default_allow) == 0: default_allow = None if default_deny is not None and len(default_deny) == 0: default_deny = None if default_allow is not None and default_deny is not None: raise _errors.SearchError("Cannot specify both `default_allow` and `default_deny` " "(got %r and %r)" % (default_allow, default_deny)) qp = _log(_xapian.QueryParser) qp.set_database(self._index) qp.set_default_op(default_op) if allow is None: allow = [key for key in self._field_actions] if deny is not None: allow = [key for key in allow if key not in deny] for field in allow: try: actions = self._field_actions[field]._actions except KeyError: actions = {} for action, kwargslist in actions.iteritems(): if action == FieldActions.INDEX_EXACT: # FIXME - need patched version of xapian to add exact prefixes #qp.add_exact_prefix(field, self._field_mappings.get_prefix(field)) qp.add_prefix(field, self._field_mappings.get_prefix(field)) if action == FieldActions.INDEX_FREETEXT: allow_field_specific = True for kwargs in kwargslist: allow_field_specific = allow_field_specific or kwargs.get('allow_field_specific', True) if not allow_field_specific: continue qp.add_prefix(field, self._field_mappings.get_prefix(field)) for kwargs in kwargslist: try: lang = kwargs['language'] my_stemmer = _log(_xapian.Stem, lang) qp.my_stemmer = my_stemmer qp.set_stemmer(my_stemmer) qp.set_stemming_strategy(qp.STEM_SOME) except KeyError: pass if default_allow is not None or default_deny is not None: if default_allow is None: default_allow = [key for key in self._field_actions] if default_deny is not None: default_allow = [key for key in default_allow if key not in default_deny] for field in default_allow: try: actions = self._field_actions[field]._actions except KeyError: actions = {} for action, kwargslist in actions.iteritems(): if action == FieldActions.INDEX_FREETEXT: qp.add_prefix('', self._field_mappings.get_prefix(field)) # FIXME - set stemming options for the default prefix return qp def _query_parse_with_prefix(self, qp, string, flags, prefix): """Parse a query, with an optional prefix. """ if prefix is None: return qp.parse_query(string, flags) else: return qp.parse_query(string, flags, prefix) def _query_parse_with_fallback(self, qp, string, prefix=None): """Parse a query with various flags. If the initial boolean pass fails, fall back to not using boolean operators. """ try: q1 = self._query_parse_with_prefix(qp, string, self._qp_flags_base | self._qp_flags_phrase | self._qp_flags_synonym | self._qp_flags_bool, prefix) except _xapian.QueryParserError, e: # If we got a parse error, retry without boolean operators (since # these are the usual cause of the parse error). q1 = self._query_parse_with_prefix(qp, string, self._qp_flags_base | self._qp_flags_phrase | self._qp_flags_synonym, prefix) qp.set_stemming_strategy(qp.STEM_NONE) try: q2 = self._query_parse_with_prefix(qp, string, self._qp_flags_base | self._qp_flags_bool, prefix) except _xapian.QueryParserError, e: # If we got a parse error, retry without boolean operators (since # these are the usual cause of the parse error). q2 = self._query_parse_with_prefix(qp, string, self._qp_flags_base, prefix) return _log(_xapian.Query, _xapian.Query.OP_AND_MAYBE, q1, q2) def query_parse(self, string, allow=None, deny=None, default_op=OP_AND, default_allow=None, default_deny=None): """Parse a query string. This is intended for parsing queries entered by a user. If you wish to combine structured queries, it is generally better to use the other query building methods, such as `query_composite` (though you may wish to create parts of the query to combine with such methods with this method). The string passed to this method can have various operators in it. In particular, it may contain field specifiers (ie, field names, followed by a colon, followed by some text to search for in that field). For example, if "author" is a field in the database, the search string could contain "author:richard", and this would be interpreted as "search for richard in the author field". By default, any fields in the database which are indexed with INDEX_EXACT or INDEX_FREETEXT will be available for field specific searching in this way - however, this can be modified using the "allow" or "deny" parameters, and also by the allow_field_specific tag on INDEX_FREETEXT fields. Any text which isn't prefixed by a field specifier is used to search the "default set" of fields. By default, this is the full set of fields in the database which are indexed with INDEX_FREETEXT and for which the search_by_default flag set (ie, if the text is found in any of those fields, the query will match). However, this may be modified with the "default_allow" and "default_deny" parameters. (Note that fields which are indexed with INDEX_EXACT aren't allowed to be used in the default list of fields.) - `string`: The string to parse. - `allow`: A list of fields to allow in the query. - `deny`: A list of fields not to allow in the query. - `default_op`: The default operator to combine query terms with. - `default_allow`: A list of fields to search for by default. - `default_deny`: A list of fields not to search for by default. Only one of `allow` and `deny` may be specified. Only one of `default_allow` and `default_deny` may be specified. If any of the entries in `allow` are not present in the configuration for the database, or are not specified for indexing (either as INDEX_EXACT or INDEX_FREETEXT), they will be ignored. If any of the entries in `deny` are not present in the configuration for the database, they will be ignored. Returns a Query object, which may be passed to the search() method, or combined with other queries. """ qp = self._prepare_queryparser(allow, deny, default_op, default_allow, default_deny) return self._query_parse_with_fallback(qp, string) def query_field(self, field, value, default_op=OP_AND): """A query for a single field. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") try: actions = self._field_actions[field]._actions except KeyError: actions = {} # need to check on field type, and stem / split as appropriate for action, kwargslist in actions.iteritems(): if action in (FieldActions.INDEX_EXACT, FieldActions.TAG, FieldActions.FACET,): prefix = self._field_mappings.get_prefix(field) if len(value) > 0: chval = ord(value[0]) if chval >= ord('A') and chval <= ord('Z'): prefix = prefix + ':' return _log(_xapian.Query, prefix + value) if action == FieldActions.INDEX_FREETEXT: qp = _log(_xapian.QueryParser) qp.set_default_op(default_op) prefix = self._field_mappings.get_prefix(field) for kwargs in kwargslist: try: lang = kwargs['language'] qp.set_stemmer(_log(_xapian.Stem, lang)) qp.set_stemming_strategy(qp.STEM_SOME) except KeyError: pass return self._query_parse_with_fallback(qp, value, prefix) return _log(_xapian.Query) def query_similar(self, ids, allow=None, deny=None, simterms=10): """Get a query which returns documents which are similar to others. The list of document IDs to base the similarity search on is given in `ids`. This should be an iterable, holding a list of strings. If any of the supplied IDs cannot be found in the database, they will be ignored. (If no IDs can be found in the database, the resulting query will not match any documents.) By default, all fields which have been indexed for freetext searching will be used for the similarity calculation. The list of fields used for this can be customised using the `allow` and `deny` parameters (only one of which may be specified): - `allow`: A list of fields to base the similarity calculation on. - `deny`: A list of fields not to base the similarity calculation on. - `simterms`: Number of terms to use for the similarity calculation. For convenience, any of `ids`, `allow`, or `deny` may be strings, which will be treated the same as a list of length 1. Regardless of the setting of `allow` and `deny`, only fields which have been indexed for freetext searching will be used for the similarity measure - all other fields will always be ignored for this purpose. """ eterms, prefixes = self._get_eterms(ids, allow, deny, simterms) # Use the "elite set" operator, which chooses the terms with the # highest query weight to use. q = _log(_xapian.Query, _xapian.Query.OP_ELITE_SET, eterms, simterms) return q def significant_terms(self, ids, maxterms=10, allow=None, deny=None): """Get a set of "significant" terms for a document, or documents. This has a similar interface to query_similar(): it takes a list of ids, and an optional specification of a set of fields to consider. Instead of returning a query, it returns a list of terms from the document (or documents), which appear "significant". Roughly, in this situation significant means that the terms occur more frequently in the specified document than in the rest of the corpus. The list is in decreasing order of "significance". By default, all terms related to fields which have been indexed for freetext searching will be considered for the list of significant terms. The list of fields used for this can be customised using the `allow` and `deny` parameters (only one of which may be specified): - `allow`: A list of fields to consider. - `deny`: A list of fields not to consider. For convenience, any of `ids`, `allow`, or `deny` may be strings, which will be treated the same as a list of length 1. Regardless of the setting of `allow` and `deny`, only fields which have been indexed for freetext searching will be considered - all other fields will always be ignored for this purpose. The maximum number of terms to return may be specified by the maxterms parameter. """ eterms, prefixes = self._get_eterms(ids, allow, deny, maxterms) terms = [] for term in eterms: pos = 0 for char in term: if not char.isupper(): break pos += 1 field = prefixes[term[:pos]] value = term[pos:] terms.append((field, value)) return terms def _get_eterms(self, ids, allow, deny, simterms): """Get a set of terms for an expand """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") if allow is not None and deny is not None: raise _errors.SearchError("Cannot specify both `allow` and `deny`") if isinstance(ids, basestring): ids = (ids, ) if isinstance(allow, basestring): allow = (allow, ) if isinstance(deny, basestring): deny = (deny, ) # Set "allow" to contain a list of all the fields to use. if allow is None: allow = [key for key in self._field_actions] if deny is not None: allow = [key for key in allow if key not in deny] # Set "prefixes" to contain a list of all the prefixes to use. prefixes = {} for field in allow: try: actions = self._field_actions[field]._actions except KeyError: actions = {} for action, kwargslist in actions.iteritems(): if action == FieldActions.INDEX_FREETEXT: prefixes[self._field_mappings.get_prefix(field)] = field # Repeat the expand until we don't get a DatabaseModifiedError while True: try: eterms = self._perform_expand(ids, prefixes, simterms) break; except _xapian.DatabaseModifiedError, e: self.reopen() return eterms, prefixes class ExpandDecider(_xapian.ExpandDecider): def __init__(self, prefixes): _xapian.ExpandDecider.__init__(self) self._prefixes = prefixes def __call__(self, term): pos = 0 for char in term: if not char.isupper(): break pos += 1 if term[:pos] in self._prefixes: return True return False def _perform_expand(self, ids, prefixes, simterms): """Perform an expand operation to get the terms for a similarity search, given a set of ids (and a set of prefixes to restrict the similarity operation to). """ # Set idquery to be a query which returns the documents listed in # "ids". idquery = _log(_xapian.Query, _xapian.Query.OP_OR, ['Q' + id for id in ids]) enq = _log(_xapian.Enquire, self._index) enq.set_query(idquery) rset = _log(_xapian.RSet) for id in ids: pl = self._index.postlist('Q' + id) try: xapid = pl.next() rset.add_document(xapid.docid) except StopIteration: pass expanddecider = _log(self.ExpandDecider, prefixes) eset = enq.get_eset(simterms, rset, 0, 1.0, expanddecider) return [term.term for term in eset] def query_all(self): """A query which matches all the documents in the database. """ return _log(_xapian.Query, '') def query_none(self): """A query which matches no documents in the database. This may be useful as a placeholder in various situations. """ return _log(_xapian.Query) def spell_correct(self, querystr, allow=None, deny=None, default_op=OP_AND, default_allow=None, default_deny=None): """Correct a query spelling. This returns a version of the query string with any misspelt words corrected. - `allow`: A list of fields to allow in the query. - `deny`: A list of fields not to allow in the query. - `default_op`: The default operator to combine query terms with. - `default_allow`: A list of fields to search for by default. - `default_deny`: A list of fields not to search for by default. Only one of `allow` and `deny` may be specified. Only one of `default_allow` and `default_deny` may be specified. If any of the entries in `allow` are not present in the configuration for the database, or are not specified for indexing (either as INDEX_EXACT or INDEX_FREETEXT), they will be ignored. If any of the entries in `deny` are not present in the configuration for the database, they will be ignored. Note that it is possible that the resulting spell-corrected query will still match no documents - the user should usually check that some documents are matched by the corrected query before suggesting it to users. """ qp = self._prepare_queryparser(allow, deny, default_op, default_allow, default_deny) try: qp.parse_query(querystr, self._qp_flags_base | self._qp_flags_phrase | self._qp_flags_synonym | self._qp_flags_bool | qp.FLAG_SPELLING_CORRECTION) except _xapian.QueryParserError: qp.parse_query(querystr, self._qp_flags_base | self._qp_flags_phrase | self._qp_flags_synonym | qp.FLAG_SPELLING_CORRECTION) corrected = qp.get_corrected_query_string() if len(corrected) == 0: if isinstance(querystr, unicode): # Encode as UTF-8 for consistency - this happens automatically # to values passed to Xapian. return querystr.encode('utf-8') return querystr return corrected def can_collapse_on(self, field): """Check if this database supports collapsing on a specified field. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") try: self._field_mappings.get_slot(field, 'collsort') except KeyError: return False return True def can_sort_on(self, field): """Check if this database supports sorting on a specified field. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") try: self._field_mappings.get_slot(field, 'collsort') except KeyError: return False return True def _get_prefix_from_term(self, term): """Get the prefix of a term. Prefixes are any initial capital letters, with the exception that R always ends a prefix, even if followed by capital letters. """ for p in xrange(len(term)): if term[p].islower(): return term[:p] elif term[p] == 'R': return term[:p+1] return term def _facet_query_never(self, facet, query_type): """Check if a facet must never be returned by a particular query type. Returns True if the facet must never be returned. Returns False if the facet may be returned - either becuase there is no entry for the query type, or because the entry is not FacetQueryType_Never. """ if query_type is None: return False if query_type not in self._facet_query_table: return False if facet not in self._facet_query_table[query_type]: return False return self._facet_query_table[query_type][facet] == _indexerconnection.IndexerConnection.FacetQueryType_Never def search(self, query, startrank, endrank, checkatleast=0, sortby=None, collapse=None, gettags=None, getfacets=None, allowfacets=None, denyfacets=None, usesubfacets=None, percentcutoff=None, weightcutoff=None, query_type=None): """Perform a search, for documents matching a query. - `query` is the query to perform. - `startrank` is the rank of the start of the range of matching documents to return (ie, the result with this rank will be returned). ranks start at 0, which represents the "best" matching document. - `endrank` is the rank at the end of the range of matching documents to return. This is exclusive, so the result with this rank will not be returned. - `checkatleast` is the minimum number of results to check for: the estimate of the total number of matches will always be exact if the number of matches is less than `checkatleast`. A value of ``-1`` can be specified for the checkatleast parameter - this has the special meaning of "check all matches", and is equivalent to passing the result of get_doccount(). - `sortby` is the name of a field to sort by. It may be preceded by a '+' or a '-' to indicate ascending or descending order (respectively). If the first character is neither '+' or '-', the sort will be in ascending order. - `collapse` is the name of a field to collapse the result documents on. If this is specified, there will be at most one result in the result set for each value of the field. - `gettags` is the name of a field to count tag occurrences in, or a list of fields to do so. - `getfacets` is a boolean - if True, the matching documents will be examined to build up a list of the facet values contained in them. - `allowfacets` is a list of the fieldnames of facets to consider. - `denyfacets` is a list of fieldnames of facets which will not be considered. - `usesubfacets` is a boolean - if True, only top-level facets and subfacets of facets appearing in the query are considered (taking precedence over `allowfacets` and `denyfacets`). - `percentcutoff` is the minimum percentage a result must have to be returned. - `weightcutoff` is the minimum weight a result must have to be returned. - `query_type` is a value indicating the type of query being performed. If not None, the value is used to influence which facets are be returned by the get_suggested_facets() function. If the value of `getfacets` is False, it has no effect. If neither 'allowfacets' or 'denyfacets' is specified, all fields holding facets will be considered (but see 'usesubfacets'). """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") if 'facets' in _checkxapian.missing_features: if getfacets is not None or \ allowfacets is not None or \ denyfacets is not None or \ usesubfacets is not None or \ query_type is not None: raise errors.SearchError("Facets unsupported with this release of xapian") if 'tags' in _checkxapian.missing_features: if gettags is not None: raise errors.SearchError("Tags unsupported with this release of xapian") if checkatleast == -1: checkatleast = self._index.get_doccount() enq = _log(_xapian.Enquire, self._index) enq.set_query(query) if sortby is not None: asc = True if sortby[0] == '-': asc = False sortby = sortby[1:] elif sortby[0] == '+': sortby = sortby[1:] try: slotnum = self._field_mappings.get_slot(sortby, 'collsort') except KeyError: raise _errors.SearchError("Field %r was not indexed for sorting" % sortby) # Note: we invert the "asc" parameter, because xapian treats # "ascending" as meaning "higher values are better"; in other # words, it considers "ascending" to mean return results in # descending order. enq.set_sort_by_value_then_relevance(slotnum, not asc) if collapse is not None: try: slotnum = self._field_mappings.get_slot(collapse, 'collsort') except KeyError: raise _errors.SearchError("Field %r was not indexed for collapsing" % collapse) enq.set_collapse_key(slotnum) maxitems = max(endrank - startrank, 0) # Always check for at least one more result, so we can report whether # there are more matches. checkatleast = max(checkatleast, endrank + 1) # Build the matchspy. matchspies = [] # First, add a matchspy for any gettags fields if isinstance(gettags, basestring): if len(gettags) != 0: gettags = [gettags] tagspy = None if gettags is not None and len(gettags) != 0: tagspy = _log(_xapian.TermCountMatchSpy) for field in gettags: try: prefix = self._field_mappings.get_prefix(field) tagspy.add_prefix(prefix) except KeyError: raise _errors.SearchError("Field %r was not indexed for tagging" % field) matchspies.append(tagspy) # add a matchspy for facet selection here. facetspy = None facetfields = [] if getfacets: if allowfacets is not None and denyfacets is not None: raise _errors.SearchError("Cannot specify both `allowfacets` and `denyfacets`") if allowfacets is None: allowfacets = [key for key in self._field_actions] if denyfacets is not None: allowfacets = [key for key in allowfacets if key not in denyfacets] # include None in queryfacets so a top-level facet will # satisfy self._facet_hierarchy.get(field) in queryfacets # (i.e. always include top-level facets) queryfacets = set([None]) if usesubfacets: # add facets used in the query to queryfacets termsiter = query.get_terms_begin() termsend = query.get_terms_end() while termsiter != termsend: prefix = self._get_prefix_from_term(termsiter.get_term()) field = self._field_mappings.get_fieldname_from_prefix(prefix) if field and FieldActions.FACET in self._field_actions[field]._actions: queryfacets.add(field) termsiter.next() for field in allowfacets: try: actions = self._field_actions[field]._actions except KeyError: actions = {} for action, kwargslist in actions.iteritems(): if action == FieldActions.FACET: # filter out non-top-level facets that aren't subfacets # of a facet in the query if usesubfacets and self._facet_hierarchy.get(field) not in queryfacets: continue # filter out facets that should never be returned for the query type if self._facet_query_never(field, query_type): continue slot = self._field_mappings.get_slot(field, 'facet') if facetspy is None: facetspy = _log(_xapian.CategorySelectMatchSpy) facettype = None for kwargs in kwargslist: facettype = kwargs.get('type', None) if facettype is not None: break if facettype is None or facettype == 'string': facetspy.add_slot(slot, True) else: facetspy.add_slot(slot) facetfields.append((field, slot, kwargslist)) if facetspy is None: # Set facetspy to False, to distinguish from no facet # calculation being performed. (This will prevent an # error being thrown when the list of suggested facets is # requested - instead, an empty list will be returned.) facetspy = False else: matchspies.append(facetspy) # Finally, build a single matchspy to pass to get_mset(). if len(matchspies) == 0: matchspy = None elif len(matchspies) == 1: matchspy = matchspies[0] else: matchspy = _log(_xapian.MultipleMatchDecider) for spy in matchspies: matchspy.append(spy) enq.set_docid_order(enq.DONT_CARE) # Set percentage and weight cutoffs if percentcutoff is not None or weightcutoff is not None: if percentcutoff is None: percentcutoff = 0 if weightcutoff is None: weightcutoff = 0 enq.set_cutoff(percentcutoff, weightcutoff) # Repeat the search until we don't get a DatabaseModifiedError while True: try: if matchspy is None: mset = enq.get_mset(startrank, maxitems, checkatleast) else: mset = enq.get_mset(startrank, maxitems, checkatleast, None, None, matchspy) break except _xapian.DatabaseModifiedError, e: self.reopen() facet_hierarchy = None if usesubfacets: facet_hierarchy = self._facet_hierarchy return SearchResults(self, enq, query, mset, self._field_mappings, tagspy, gettags, facetspy, facetfields, facet_hierarchy, self._facet_query_table.get(query_type)) def iterids(self): """Get an iterator which returns all the ids in the database. The unqiue_ids are currently returned in binary lexicographical sort order, but this should not be relied on. Note that the iterator returned by this method may raise a xapian.DatabaseModifiedError exception if modifications are committed to the database while the iteration is in progress. If this happens, the search connection must be reopened (by calling reopen) and the iteration restarted. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") return _indexerconnection.PrefixedTermIter('Q', self._index.allterms()) def get_document(self, id): """Get the document with the specified unique ID. Raises a KeyError if there is no such document. Otherwise, it returns a ProcessedDocument. """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") while True: try: postlist = self._index.postlist('Q' + id) try: plitem = postlist.next() except StopIteration: # Unique ID not found raise KeyError('Unique ID %r not found' % id) try: postlist.next() raise _errors.IndexerError("Multiple documents " #pragma: no cover "found with same unique ID") except StopIteration: # Only one instance of the unique ID found, as it should be. pass result = ProcessedDocument(self._field_mappings) result.id = id result._doc = self._index.get_document(plitem.docid) return result except _xapian.DatabaseModifiedError, e: self.reopen() def iter_synonyms(self, prefix=""): """Get an iterator over the synonyms. - `prefix`: if specified, only synonym keys with this prefix will be returned. The iterator returns 2-tuples, in which the first item is the key (ie, a 2-tuple holding the term or terms which will be synonym expanded, followed by the fieldname specified (or None if no fieldname)), and the second item is a tuple of strings holding the synonyms for the first item. These return values are suitable for the dict() builtin, so you can write things like: >>> conn = _indexerconnection.IndexerConnection('foo') >>> conn.add_synonym('foo', 'bar') >>> conn.add_synonym('foo bar', 'baz') >>> conn.add_synonym('foo bar', 'foo baz') >>> conn.flush() >>> conn = SearchConnection('foo') >>> dict(conn.iter_synonyms()) {('foo', None): ('bar',), ('foo bar', None): ('baz', 'foo baz')} """ if self._index is None: raise _errors.SearchError("SearchConnection has been closed") return _indexerconnection.SynonymIter(self._index, self._field_mappings, prefix) def get_metadata(self, key): """Get an item of metadata stored in the connection. This returns a value stored by a previous call to IndexerConnection.set_metadata. If the value is not found, this will return the empty string. """ if self._index is None: raise _errors.IndexerError("SearchConnection has been closed") if not hasattr(self._index, 'get_metadata'): raise _errors.IndexerError("Version of xapian in use does not support metadata") return _log(self._index.get_metadata, key) if __name__ == '__main__': import doctest, sys doctest.testmod (sys.modules[__name__]) xappy-0.5/xappy/searchconnection_doctest1.txt0000644000175000017500000001403510736164666021410 0ustar richardrichard >>> from datastructures import * >>> from fieldactions import * >>> from indexerconnection import * Open a connection for indexing: >>> iconn = IndexerConnection('foo') >>> iconn.add_field_action('author', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('title', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('category', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('text', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('author', FieldActions.INDEX_FREETEXT, weight=2) >>> iconn.add_field_action('title', FieldActions.INDEX_FREETEXT, weight=5) >>> iconn.add_field_action('category', FieldActions.INDEX_EXACT) >>> iconn.add_field_action('category', FieldActions.SORTABLE) >>> iconn.add_field_action('category', FieldActions.COLLAPSE) >>> iconn.add_field_action('text', FieldActions.INDEX_FREETEXT, language='en') Add a set of documents: >>> for i in xrange(200): ... doc = UnprocessedDocument() ... doc.fields.append(Field('author', 'Richard Boulton')) ... doc.fields.append(Field('category', 'Cat %d' % ((i + 5) % 20))) ... doc.fields.append(Field('text', 'This document is a basic test document.')) ... doc.fields.append(Field('title', 'Test document %d' % i)) ... doc.fields.append(Field('text', 'More test text about this document.')) ... id = iconn.add(doc) We can get a document from the indexer connection, even before flushing, by using the get_document method. If the id specified is not found, an error is raised. >>> iconn.get_document('1').data['category'] ['Cat 6'] >>> print iconn.get_document('1000').data['category'] Traceback (most recent call last): ... KeyError: "Unique ID '1000' not found" If we open a search connection for a database which doesn't exist, we get an exception: >>> sconn = SearchConnection('notpresent') Traceback (most recent call last): ... DatabaseOpeningError: Couldn't detect type of database If we open a search connection before flushing, we can't see the recent modifications: >>> sconn = SearchConnection('foo') >>> sconn.get_document('1').data['category'] Traceback (most recent call last): ... KeyError: "Unique ID '1' not found" Finally, we get round to flushing the indexer: >>> iconn.flush() We still can't see the document from the search connection. >>> sconn.get_document('1').data['category'] Traceback (most recent call last): ... KeyError: "Unique ID '1' not found" Now, open a new search connection - we can see the document: >>> sconn = SearchConnection('foo') >>> sconn.get_document('1').data['category'] ['Cat 6'] >>> q = sconn.query_parse('document') >>> results = sconn.search(q, 0, 30) >>> len(results) 30 >>> [result.id for result in results] ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d'] >>> result = results.get_hit(0) >>> result.data['text'] ['This document is a basic test document.', 'More test text about this document.'] >>> result.highlight('text') ['This document is a basic test document.', 'More test text about this document.'] >>> result.summarise('text') 'This document is a basic test document.\nMore test text about this document.' >>> result.summarise('text', maxlen=20) 'This document is a ..' >>> result.summarise('title', maxlen=20) 'Test document 0' If we collapse on categories, we just get the top result in each category: >>> [result.id for result in sconn.search(q, 0, 30, collapse='category')] ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '10', '11', '12', '13'] We can't collapse on categories which we're indexed for it: >>> [result.id for result in sconn.search(q, 0, 30, collapse='author')] Traceback (most recent call last): ... SearchError: Field 'author' was not indexed for collapsing If we sort by category, we get a different order of results: >>> [':'.join((result.id, result.data['category'][0])) for result in sconn.search(q, 0, 30, sortby='-category')] ['4:Cat 9', '18:Cat 9', '2c:Cat 9', '40:Cat 9', '54:Cat 9', '68:Cat 9', '7c:Cat 9', '90:Cat 9', 'a4:Cat 9', 'b8:Cat 9', '3:Cat 8', '17:Cat 8', '2b:Cat 8', '3f:Cat 8', '53:Cat 8', '67:Cat 8', '7b:Cat 8', '8f:Cat 8', 'a3:Cat 8', 'b7:Cat 8', '2:Cat 7', '16:Cat 7', '2a:Cat 7', '3e:Cat 7', '52:Cat 7', '66:Cat 7', '7a:Cat 7', '8e:Cat 7', 'a2:Cat 7', 'b6:Cat 7'] We can sort in ascending order instead: >>> [':'.join((result.id, result.data['category'][0])) for result in sconn.search(q, 0, 30, sortby='+category')] ['f:Cat 0', '23:Cat 0', '37:Cat 0', '4b:Cat 0', '5f:Cat 0', '73:Cat 0', '87:Cat 0', '9b:Cat 0', 'af:Cat 0', 'c3:Cat 0', '10:Cat 1', '24:Cat 1', '38:Cat 1', '4c:Cat 1', '60:Cat 1', '74:Cat 1', '88:Cat 1', '9c:Cat 1', 'b0:Cat 1', 'c4:Cat 1', '5:Cat 10', '19:Cat 10', '2d:Cat 10', '41:Cat 10', '55:Cat 10', '69:Cat 10', '7d:Cat 10', '91:Cat 10', 'a5:Cat 10', 'b9:Cat 10'] Ascending order is the default, so we don't actually need the '+': >>> [':'.join((result.id, result.data['category'][0])) for result in sconn.search(q, 0, 30, sortby='category')] ['f:Cat 0', '23:Cat 0', '37:Cat 0', '4b:Cat 0', '5f:Cat 0', '73:Cat 0', '87:Cat 0', '9b:Cat 0', 'af:Cat 0', 'c3:Cat 0', '10:Cat 1', '24:Cat 1', '38:Cat 1', '4c:Cat 1', '60:Cat 1', '74:Cat 1', '88:Cat 1', '9c:Cat 1', 'b0:Cat 1', 'c4:Cat 1', '5:Cat 10', '19:Cat 10', '2d:Cat 10', '41:Cat 10', '55:Cat 10', '69:Cat 10', '7d:Cat 10', '91:Cat 10', 'a5:Cat 10', 'b9:Cat 10'] We can't collapse on categories which we're indexed for it: >>> [result.id for result in sconn.search(q, 0, 30, sortby='author')] Traceback (most recent call last): ... SearchError: Field 'author' was not indexed for sorting We can collapse and sort in a single search: >>> [':'.join((result.id, result.data['category'][0])) for result in sconn.search(q, 0, 30, collapse="category", sortby='-category')] ['4:Cat 9', '3:Cat 8', '2:Cat 7', '1:Cat 6', '0:Cat 5', '13:Cat 4', '12:Cat 3', '11:Cat 2', 'e:Cat 19', 'd:Cat 18', 'c:Cat 17', 'b:Cat 16', 'a:Cat 15', '9:Cat 14', '8:Cat 13', '7:Cat 12', '6:Cat 11', '5:Cat 10', '10:Cat 1', 'f:Cat 0'] Tidy up after ourselves: >>> sconn.close() xappy-0.5/xappy/searchconnection_doctest2.txt0000644000175000017500000005214211005445111021363 0ustar richardrichard >>> from datastructures import * >>> from fieldactions import * >>> from indexerconnection import * Open a connection for indexing: >>> iconn = IndexerConnection('foo') >>> iconn.add_field_action('author', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('title', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('category', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('text', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('author', FieldActions.INDEX_FREETEXT, weight=2) >>> iconn.add_field_action('title', FieldActions.INDEX_FREETEXT, weight=5) >>> iconn.add_field_action('category', FieldActions.INDEX_EXACT) >>> iconn.add_field_action('category', FieldActions.SORTABLE) >>> iconn.add_field_action('category', FieldActions.COLLAPSE) >>> iconn.add_field_action('category', FieldActions.FACET) >>> iconn.add_field_action('text', FieldActions.INDEX_FREETEXT, language='en', ... spell=True, stop=('basic',)) >>> iconn.add_field_action('date', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('date', FieldActions.COLLAPSE) >>> iconn.add_field_action('date', FieldActions.SORTABLE, type='date') >>> iconn.add_field_action('date', FieldActions.COLLAPSE) >>> iconn.add_field_action('price', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('price', FieldActions.SORTABLE, type='float') >>> iconn.add_field_action('price', FieldActions.COLLAPSE) >>> iconn.add_field_action('price', FieldActions.FACET, type='float') >>> iconn.add_field_action('price3', FieldActions.SORTABLE, type='float') >>> iconn.add_field_action('price3', FieldActions.FACET, type='float') >>> iconn.add_field_action('price3', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('facet1', FieldActions.FACET) >>> iconn.add_field_action('facet2', FieldActions.FACET) >>> iconn.add_field_action('facet3', FieldActions.FACET) >>> iconn.add_field_action('facet4', FieldActions.FACET, type='float') >>> iconn.add_field_action('facet5', FieldActions.FACET) >>> iconn.add_field_action('facet6', FieldActions.FACET) >>> iconn.add_field_action('facet7', FieldActions.FACET) >>> iconn.add_field_action('facet8', FieldActions.FACET, type='float') >>> iconn.add_field_action('tag', FieldActions.TAG) # Add this, for a regression test. >>> iconn.add_field_action('facet9', FieldActions.FACET, type='float') >>> iconn.add_field_action('facet9', FieldActions.SORTABLE) A field can only be sorted according to one type: >>> iconn.add_field_action('date', FieldActions.SORTABLE, type='float') Traceback (most recent call last): ... IndexerError: Field 'date' is already marked for sorting, with a different sort type If we set the sort type to an unknown value, we get errors when it is used: >>> iconn.add_field_action('price2', FieldActions.SORTABLE, type='unknown') >>> doc = UnprocessedDocument() >>> doc.fields.append(Field('price2', '1.0')) >>> iconn.process(doc) Traceback (most recent call last): ... IndexerError: Unknown sort type 'unknown' for field 'price2' Make another database which doesn't have any facet fields:: >>> iconn2 = IndexerConnection('foo2') >>> iconn2.add_field_action('author', FieldActions.STORE_CONTENT) Add a set of documents, which dates and prices, to test sorting: >>> for i in xrange(200): ... doc = UnprocessedDocument() ... doc.fields.append(Field('author', 'Richard Boulton')) ... doc.fields.append(Field('category', 'Cat %d' % ((i + 5) % 20))) ... doc.fields.append(Field('text', 'This document is a basic test document.')) ... doc.fields.append(Field('title', 'Test document %d' % i)) ... doc.fields.append(Field('text', 'More test text about this document.')) ... doc.fields.append(Field('date', '2007%02d%02d' % (i % 12 + 1, i // 12 + 1))) ... doc.fields.append(Field('price', '%f' % ((float(i) / 7) % 10))) ... doc.fields.append(Field('price3', '%f' % ((float(i) * 6.7)))) ... doc.fields.append(Field('facet1', '%d' % (i // 40))) ... doc.fields.append(Field('facet2', '%d' % (i // 20))) ... doc.fields.append(Field('facet3', '%d' % (i // 12))) ... doc.fields.append(Field('facet4', '%d' % (i // 8))) ... doc.fields.append(Field('facet5', '%d' % (i // 5))) ... doc.fields.append(Field('facet6', '0')) ... doc.fields.append(Field('facet7', '2000')) ... doc.fields.append(Field('facet7', '2001')) ... doc.fields.append(Field('facet7', '%d' % (i % 2))) ... doc.fields.append(Field('facet8', '2000')) ... doc.fields.append(Field('facet8', '2001')) ... doc.fields.append(Field('facet8', '%d' % (i % 2))) ... doc.fields.append(Field('facet9', '%d' % (i // 5))) ... doc.fields.append(Field('tag', '%d' % (i % 5))) ... doc.fields.append(Field('tag', '%d' % (i % 9))) ... doc.fields.append(Field('tag', '%d' % (i // 5))) ... id = iconn.add(doc) ... id = iconn2.add(doc) Add some synonyms: >>> iconn.add_synonym('document', 'record') >>> iconn.add_synonym('basic test', 'exam', original_field='text') >>> iconn.add_synonym('document', 'notrecord') >>> iconn.add_synonym('documents', 'notrecord') >>> iconn.remove_synonym('document', 'notrecord') >>> iconn.clear_synonyms('documents') >>> iconn.flush() >>> dict(iconn.iter_synonyms()) {('document', None): ('record',), ('basic test', 'text'): ('exam',)} >>> dict(iconn.iter_synonyms('doc')) {('document', None): ('record',)} >>> dict(iconn.iter_synonyms('toc')) {} Now, open a search connection: >>> sconn = SearchConnection('foo') >>> sconn2 = SearchConnection('foo2') We can append a close handler to notify us when the connection is closed. >>> def closehandler(path, userdata): ... print "Closing connection at path %s: %s" % (path, userdata) >>> sconn.append_close_handler(closehandler, "Conn1") >>> sconn2.append_close_handler(closehandler, "Conn2") First, check the fallback handling for queries with invalid boolean operations: >>> q = sconn.query_parse('AND document') >>> str(q) 'Xapian::Query(((and:(pos=1) AND (Zdocument:(pos=2) SYNONYM record:(pos=2))) AND_MAYBE (and:(pos=1) AND document:(pos=2))))' Check that spelling correction works: >>> sconn.spell_correct('docment') 'document' >>> sconn.spell_correct('document') 'document' >>> sconn.spell_correct(u'docment') 'document' >>> sconn.spell_correct(u'document') 'document' Check that stopwording worked: >>> q = sconn.query_parse('basic') >>> results = sconn.search(q, 0, 30) >>> [result.id for result in results] [] Check that synonyms work: >>> dict(sconn.iter_synonyms()) {('document', None): ('record',), ('basic test', 'text'): ('exam',)} >>> q = sconn.query_parse('document') >>> str(q) 'Xapian::Query(((Zdocument:(pos=1) SYNONYM record:(pos=1)) AND_MAYBE document:(pos=1)))' Remove the synonyms for the remaining tests: >>> iconn.clear_synonyms('document') >>> iconn.clear_synonyms('basic test', field='text') >>> iconn.flush() >>> sconn.reopen() >>> dict(sconn.iter_synonyms()) {} Now, parse a simple query. >>> q = sconn.query_parse('document') >>> str(q) 'Xapian::Query((Zdocument:(pos=1) AND_MAYBE document:(pos=1)))' >>> results = sconn.search(q, 0, 30) >>> [result.id for result in results] ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d'] >>> results = sconn.search(q, 0, 30, sortby="price") >>> prev_price = results[0].data['price'] >>> for price in (result.data['price'] for result in results): ... assert(price >= prev_price) ... prev_price = price >>> [int(result.id, 16) for result in results] [0, 70, 140, 1, 71, 141, 2, 72, 142, 3, 73, 143, 4, 74, 144, 5, 75, 145, 6, 76, 146, 7, 77, 147, 8, 78, 148, 9, 79, 149] >>> [result.data['price'] for result in results] [['0.000000'], ['0.000000'], ['0.000000'], ['0.142857'], ['0.142857'], ['0.142857'], ['0.285714'], ['0.285714'], ['0.285714'], ['0.428571'], ['0.428571'], ['0.428571'], ['0.571429'], ['0.571429'], ['0.571429'], ['0.714286'], ['0.714286'], ['0.714286'], ['0.857143'], ['0.857143'], ['0.857143'], ['1.000000'], ['1.000000'], ['1.000000'], ['1.142857'], ['1.142857'], ['1.142857'], ['1.285714'], ['1.285714'], ['1.285714']] >>> results = sconn.search(q, 0, 30, sortby="-price") >>> prev_price = results[0].data['price'] >>> for price in (result.data['price'] for result in results): ... assert(price <= prev_price) ... prev_price = price >>> [int(result.id, 16) for result in results] [69, 139, 68, 138, 67, 137, 66, 136, 65, 135, 64, 134, 63, 133, 62, 132, 61, 131, 60, 130, 59, 129, 199, 58, 128, 198, 57, 127, 197, 56] >>> results = sconn.search(q, 0, 30, sortby="date") >>> prev_date = results[0].data['date'] >>> for date in (result.data['date'] for result in results): ... assert(date >= prev_date) ... prev_date = date >>> [int(result.id, 16) for result in results] [0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156, 168, 180, 192, 1, 13, 25, 37, 49, 61, 73, 85, 97, 109, 121, 133, 145] >>> results = sconn.search(q, 0, 30, sortby="-date") >>> prev_date = results[0].data['date'] >>> for date in (result.data['date'] for result in results): ... assert(date <= prev_date) ... prev_date = date >>> [int(result.id, 16) for result in results] [191, 179, 167, 155, 143, 131, 119, 107, 95, 83, 71, 59, 47, 35, 23, 11, 190, 178, 166, 154, 142, 130, 118, 106, 94, 82, 70, 58, 46, 34] Get a list of the facets and tags relevant for the search >>> results2 = sconn.search(sconn.query_all(), 0, 30, checkatleast=200, ... sortby="-date", gettags=('tag'), getfacets=True) >>> [int(result.id, 16) for result in results2] [191, 179, 167, 155, 143, 131, 119, 107, 95, 83, 71, 59, 47, 35, 23, 11, 190, 178, 166, 154, 142, 130, 118, 106, 94, 82, 70, 58, 46, 34] >>> results2.get_top_tags('tag', 8) [('0', 62), ('1', 62), ('3', 61), ('2', 60), ('4', 60), ('5', 27), ('7', 27), ('6', 26)] >>> [(facet[0], len(facet[1])) for facet in results2.get_suggested_facets(maxfacets=10)] [('price3', 7), ('facet1', 5), ('facet4', 5), ('facet2', 10), ('facet9', 4), ('price', 4), ('facet8', 2), ('facet3', 17), ('category', 20), ('facet5', 40)] >>> [(facet[0], facet[1]) for facet in results2.get_suggested_facets(maxfacets=5)] [('price3', [((0.0, 194.30000000000001), 30), ((201.0, 395.30000000000001), 30), ((402.0, 596.29999999999995), 30), ((603.0, 797.29999999999995), 30), ((804.0, 998.29999999999995), 30), ((1005.0, 1199.3), 30), ((1206.0, 1333.3), 20)]), ('facet1', [('0', 40), ('1', 40), ('2', 40), ('3', 40), ('4', 40)]), ('facet4', [((0.0, 4.0), 40), ((5.0, 9.0), 40), ((10.0, 14.0), 40), ((15.0, 19.0), 40), ((20.0, 24.0), 40)]), ('facet2', [('0', 20), ('1', 20), ('2', 20), ('3', 20), ('4', 20), ('5', 20), ('6', 20), ('7', 20), ('8', 20), ('9', 20)]), ('facet9', [((0.0, 9.0), 50), ((10.0, 19.0), 50), ((20.0, 29.0), 50), ((30.0, 39.0), 50)])] >>> [(facet[0], len(facet[1])) for facet in results2.get_suggested_facets(maxfacets=5, required_facets='price3')] [('price3', 7), ('facet1', 5), ('facet4', 5), ('facet2', 10), ('facet9', 4)] >>> [(facet[0], len(facet[1])) for facet in results2.get_suggested_facets(maxfacets=5, required_facets='facet8')] [('price3', 7), ('facet1', 5), ('facet4', 5), ('facet2', 10), ('facet8', 2)] >>> [(facet[0], len(facet[1])) for facet in results2.get_suggested_facets(maxfacets=5, required_facets=('facet8', 'price', 'facet7'))] [('price3', 7), ('facet1', 5), ('price', 4), ('facet8', 2), ('facet7', 4)] >>> [(facet[0], len(facet[1])) for facet in results2.get_suggested_facets(maxfacets=5, required_facets=('facet8', 'price', 'facet7', 'price3', 'facet1'))] [('price3', 7), ('facet1', 5), ('price', 4), ('facet8', 2), ('facet7', 4)] >>> [(facet[0], len(facet[1])) for facet in results2.get_suggested_facets(maxfacets=5, required_facets=('facet8', 'price', 'facet7', 'price3', 'facet1', 'facet4'))] [('price3', 7), ('facet1', 5), ('facet4', 5), ('price', 4), ('facet8', 2), ('facet7', 4)] We can use a facet to restrict the search results: >>> results3 = sconn.search(sconn.query_facet('price3', (0.0, 200.0)), 0, 30, ... checkatleast=200, getfacets=True) Check that the restriction was satisfied by all the results: >>> False in [float(result.data['price3'][0]) <= 200 for result in results3] False Getting the list of facets when there is a facet restriction in place will return a different selection (based on the documents satisfying the restriction): >>> [(facet[0], len(facet[1])) for facet in results3.get_suggested_facets(maxfacets=5)] [('facet5', 6), ('facet9', 6), ('price', 5), ('price3', 4), ('facet4', 4)] The suggestions for the facet we've already restricted by are for sub-values within the range: >>> results3.get_suggested_facets(maxfacets=5)[3] ('price3', [((0.0, 46.899999999999999), 8), ((53.600000000000001, 93.799999999999997), 7), ((100.5, 147.40000000000001), 8), ((154.09999999999999, 194.30000000000001), 7)]) Regression test: this used to give an error >>> results3 = sconn.search(sconn.query_facet('facet9', (0.0, 5.0)), 0, 30, ... checkatleast=200, getfacets=True) A facet which only contains one value in the matching documents will never be returned as a suggestion:: >>> results3 = sconn.search(sconn.query_facet('facet5', '5'), 0, 30, ... checkatleast=200, getfacets=True, ... allowfacets=('facet5', 'facet6')) >>> results3.matches_estimated 5 >>> results3.get_suggested_facets() [] Facet fields may contain multiple values in a single document, unless the type is "float" (in which case, only the final value specified in a given document will be stored). Therefore, we expect facet8 to _not_ include the 2000 and 2001 values, but facet7 should include them: >>> results3 = sconn.search(sconn.query_all(), 0, 30, ... checkatleast=200, getfacets=True, ... allowfacets=('facet7', 'facet8')) >>> results3.get_suggested_facets() [('facet8', [((0.0, 0.0), 100), ((1.0, 1.0), 100)]), ('facet7', [('0', 100), ('1', 100), ('2000', 200), ('2001', 200)])] Even if the database doesn't contain any facets, getting the list of suggested facets should return an empty list (this is a regression test - this used to raise an exception). >>> results3 = sconn2.search(sconn2.query_all(), 0, 30, ... checkatleast=200, getfacets=True) >>> results3.get_suggested_facets() [] We can also filter the results by a range of the sortable values - for example, dates: >>> fq = sconn.query_filter(q, sconn.query_range('date', '20070205', '20070207')) >>> results = sconn.search(fq, 0, 30, sortby="date") >>> [int(result.id, 16) for result in results] [49, 61, 73] >>> for result in results: ... print "%r,%r" % (result.data['date'], result.get_value('date', 'collsort')) ['20070205'],'20070205' ['20070206'],'20070206' ['20070207'],'20070207' We can specify semi-infinite ranges by specifying None for one of the endpoints: >>> fq = sconn.query_filter(q, sconn.query_range('date', None, '20070104')) >>> results = sconn.search(fq, 0, 30, sortby="date") >>> for result in results: ... print "%r,%r" % (result.data['date'], result.get_value('date', 'collsort')) ['20070101'],'20070101' ['20070102'],'20070102' ['20070103'],'20070103' ['20070104'],'20070104' >>> fq = sconn.query_filter(q, sconn.query_range('date', '20071214', None)) >>> results = sconn.search(fq, 0, 30, sortby="date") >>> for result in results: ... print "%r,%r" % (result.data['date'], result.get_value('date', 'collsort')) ['20071214'],'20071214' ['20071215'],'20071215' ['20071216'],'20071216' We can use a filter to exclude results which match a particular sub-query, instead of to include only those which match. >>> fq = sconn.query_filter(q, sconn.query_range('date', '20070105', '20071214'), exclude=True) >>> results = sconn.search(fq, 0, 30, sortby="date") >>> [int(result.id, 16) for result in results] [0, 12, 24, 36, 179, 191] >>> for result in results: ... print "%r,%r" % (result.data['date'], result.get_value('date', 'collsort')) ['20070101'],'20070101' ['20070102'],'20070102' ['20070103'],'20070103' ['20070104'],'20070104' ['20071215'],'20071215' ['20071216'],'20071216' Or we can restrict by numerical range: >>> fq = sconn.query_filter(q, sconn.query_range('price', '0.1428', '0.5')) >>> results = sconn.search(fq, 0, 30, sortby="date") >>> [int(result.id, 16) for result in results] [72, 1, 73, 2, 3, 141, 142, 71, 143] >>> [(result.data['price'][0]) for result in results] ['0.285714', '0.142857', '0.428571', '0.285714', '0.428571', '0.142857', '0.285714', '0.142857', '0.428571'] >>> fq = sconn.query_range('price', '0.1428', '0.5') >>> results = sconn.search(fq, 0, 30, sortby="date") >>> [int(result.id, 16) for result in results] [72, 1, 73, 2, 3, 141, 142, 71, 143] If the end of the range is lower than the start, no results can match >>> fq = sconn.query_filter(q, sconn.query_range('price', '0.5', '0.1428')) >>> results = sconn.search(fq, 0, 30, sortby="date") >>> [int(result.id, 16) for result in results] [] We can also adjust the weights of one query using a second query: >>> q = sconn.query_adjust(q, sconn.query_parse('cat')) >>> str(q) 'Xapian::Query(((Zdocument:(pos=1) AND_MAYBE document:(pos=1)) AND_MAYBE (Zcat:(pos=1) AND_MAYBE cat:(pos=1))))' If invalid values are supplied to query_range, a SearchError is raised >>> sconn.query_range('date', '0.1428', '0.5') Traceback (most recent call last): ... SearchError: Value supplied to field 'date' must be a valid date: was '0.1428': error is 'Unrecognised date format' Do a search which matches all documents: >>> q = sconn.query_all() >>> str(q) 'Xapian::Query()' >>> results = sconn.search(q, 0, 30) >>> len(results) 30 >>> results Do a search which uses a restricted set of default fields: >>> q = sconn.query_parse('richard', default_allow='author') >>> str(q) 'Xapian::Query((ZXArichard:(pos=1) AND_MAYBE XArichard:(pos=1)))' >>> q = sconn.query_parse('richard', default_deny='category') >>> str(q) 'Xapian::Query(((ZXArichard:(pos=1) OR ZXBrichard:(pos=1) OR ZXDrichard:(pos=1)) AND_MAYBE (XArichard:(pos=1) OR XBrichard:(pos=1) OR XDrichard:(pos=1))))' Do a search which multiplies the weights by 2: >>> q = sconn.query_multweight(sconn.query_parse('richard', default_allow='author'), 2) >>> str(q) 'Xapian::Query(2 * (ZXArichard:(pos=1) AND_MAYBE XArichard:(pos=1)))' >>> q2 = sconn.query_parse('richard', default_deny='author') >>> q = sconn.query_composite(sconn.OP_OR, (q, q2)) >>> str(q) 'Xapian::Query((2 * (ZXArichard:(pos=1) AND_MAYBE XArichard:(pos=1)) OR ((ZXBrichard:(pos=1) OR ZXDrichard:(pos=1)) AND_MAYBE (XBrichard:(pos=1) OR XDrichard:(pos=1)))))' Do a similarity search >>> q = sconn.query_parse('document (2 OR 5 OR 8)') >>> results = sconn.search(q, 0, 5, sortby="date") >>> len(results) 3 >>> ids = [result.id for result in results] >>> len(ids) 3 >>> sconn.significant_terms(ids, maxterms=5) [('title', '8'), ('title', '5'), ('title', '2'), ('title', 'test'), ('title', 'document')] >>> q2 = sconn.query_similar(ids, simterms=5) >>> str(q2) 'Xapian::Query((XB8 ELITE_SET 5 XB5 ELITE_SET 5 XB2 ELITE_SET 5 XBtest ELITE_SET 5 XBdocument))' >>> q2 = sconn.query_similar(ids, simterms=5, allow='text') >>> str(q2) 'Xapian::Query((XDdocument ELITE_SET 5 XDthis ELITE_SET 5 XDtest ELITE_SET 5 XDtext ELITE_SET 5 XDmore))' Try a search with various weight cutoff restrictions: >>> results = sconn.search(sconn.query_parse('richard OR 7 OR 7 OR 8'), 0, 5, sortby="date") >>> [(result.id, result.percent, int(result.weight * 10)) for result in results] [('7', 55, 326), ('8', 27, 163)] >>> results = sconn.search(sconn.query_parse('richard OR 7 OR 7 OR 8'), 0, 5, sortby="date", percentcutoff=30) >>> [(result.id, result.percent, int(result.weight * 10)) for result in results] [('7', 55, 326)] >>> results = sconn.search(sconn.query_parse('richard OR 7 OR 7 OR 8'), 0, 5, sortby="date", weightcutoff=20) >>> [(result.id, result.percent, int(result.weight * 10)) for result in results] [('7', 55, 326)] >>> results = sconn.search(sconn.query_parse('richard OR 7 OR 7 OR 8'), 0, 5, sortby="date", percentcutoff=56) >>> [(result.id, result.percent, int(result.weight * 10)) for result in results] [] >>> results = sconn.search(sconn.query_parse('richard OR 7 OR 7 OR 8'), 0, 5, sortby="date", weightcutoff=33) >>> [(result.id, result.percent, int(result.weight * 10)) for result in results] [] Do a similarity search with an ID which isn't in the database: >>> q2 = sconn.query_similar('foo', simterms=5) >>> str(q2) 'Xapian::Query()' Check the expand decider used by similarity reordering of queries. >>> res = sconn.search(q2, 0, 5) >>> ed = res._make_expand_decider('title') >>> ed('foo') False >>> ed('XBA:foo') False >>> ed('XBAfoo') False >>> ed('XB:foo') True >>> ed('XBfoo') True >>> ed('ZXBfoo') True >>> ed('ZXBfoo') True Find the interesting terms in a set of documents: >>> [(docid, sconn.significant_terms(docid, 3)) for docid in sconn.iterids()][:3] [('0', [('title', '0'), ('title', 'test'), ('title', 'document')]), ('1', [('title', '1'), ('title', 'test'), ('title', 'document')]), ('10', [('title', '16'), ('title', 'test'), ('title', 'document')])] Tidy up after ourselves: >>> sconn.close() Closing connection at path foo: Conn1 >>> del sconn >>> del sconn2 >>> del result >>> del results >>> del results2 >>> del results3 Closing connection at path foo2: Conn2 xappy-0.5/xappy/searchconnection_doctest3.txt0000644000175000017500000000607410752030064021374 0ustar richardrichard This file mainly contains tests for error handling conditions. >>> from datastructures import * >>> from fieldactions import * >>> from indexerconnection import * Open a connection for indexing: >>> iconn = IndexerConnection('foo') >>> iconn.add_field_action('title', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('text', FieldActions.STORE_CONTENT) >>> iconn.add_field_action('text', FieldActions.INDEX_FREETEXT, language='en', ... spell=True, stop=('basic',)) >>> iconn.add_field_action('tag', FieldActions.TAG) >>> iconn.add_field_action('tag2', FieldActions.TAG) >>> for i in xrange(20): ... doc = UnprocessedDocument() ... doc.fields.append(Field('text', 'This is basic test document %d.' % i)) ... doc.fields.append(Field('title', 'Test document %d' % i)) ... id = iconn.add(doc) Test getting and setting metadata: >>> iconn.get_metadata('foo') '' >>> iconn.set_metadata('foo', 'bar') >>> iconn.get_metadata('foo') 'bar' >>> iconn.flush() Now, open a search connection: >>> sconn = SearchConnection('foo') Now, parse a simple query. >>> q = sconn.query_parse('document') >>> results = sconn.search(q, 0, 20) >>> [result.id for result in results] ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', '10', '11', '12', '13'] >>> result = results.get_hit(0) >>> result.summarise('text') 'This is basic test document 0.' >>> result.summarise('title') 'Test document 0' The maxlen (in characters) can be specified: >>> result.summarise('text', 5) 'This..' If it's specified as a string (eg, unconverted output from a webapp) it should still work: >>> result.summarise('text', '5') 'This..' Asking for a summary of a field which isn't known will raise a KeyError. >>> result.summarise('titl') Traceback (most recent call last): ... KeyError: 'titl' Asking for a top tags of a field when no fields were specified for counting tags will raise a SearchError. >>> results.get_top_tags('title', 100) Traceback (most recent call last): ... SearchError: Field 'title' was not specified for getting tags Asking for tags in a field which wasn't indexed for tagging will return an error: >>> results = sconn.search(q, 0, 20, gettags='title') Traceback (most recent call last): ... SearchError: Field 'title' was not indexed for tagging Asking for top tags of a field which wasn't specified for counting tags will raise a SearchError. >>> results = sconn.search(q, 0, 20, gettags='tag') >>> results.get_top_tags('tag', 100) [] >>> results.get_top_tags('tag2', 100) Traceback (most recent call last): ... SearchError: Field 'tag2' was not specified for getting tags >>> results.get_top_tags('text', 100) Traceback (most recent call last): ... SearchError: Field 'text' was not specified for getting tags Asking for suggested facets if none were calculated raises a SearchError: >>> results.get_suggested_facets('text') Traceback (most recent call last): ... SearchError: Facet selection wasn't enabled when the search was run Test getting metadata: >>> sconn.get_metadata('foo1') '' >>> sconn.get_metadata('foo') 'bar' xappy-0.5/xappy.egg-info/0000755000175000017500000000000011005556727015174 5ustar richardrichardxappy-0.5/xappy.egg-info/PKG-INFO0000644000175000017500000000312511005556727016272 0ustar richardrichardMetadata-Version: 1.0 Name: xappy Version: 0.5 Summary: Easy-to-use interface to the Xapian search engine Home-page: http://code.google.com/p/xappy Author: Richard Boulton Author-email: richard@lemurconsulting.com License: GPL Download-URL: http://xappy.googlecode.com/files/xappy-0.5.tar.gz Description: The "xappy" python module is an easy-to-use interface to the Xapian search engine. Xapian provides a low level interface, dealing with terms and documents, but not really worrying about where terms come from, or how to build searches to match the way in which data has been indexed. In contrast, "xappy" allows you to design a field structure, specifying what kind of information is held in particular fields, and then uses this field structure to index data appropriately, and to build and perform searches. Xappy is not yet stable - in particular, both the API and database format will change in future releases. If you wish to use it, we recommend that you subscribe to the xappy-discuss mailing list (see http://groups.google.com/group/xappy-discuss) to keep up-to-date with changes to Xappy. Platform: Any Classifier: Development Status :: 3 - Alpha Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Programming Language :: C++ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search Classifier: Operating System :: MacOS Classifier: Operating System :: Microsoft Classifier: Operating System :: POSIX xappy-0.5/xappy.egg-info/SOURCES.txt0000644000175000017500000001211611005556727017061 0ustar richardrichardAUTHORS COPYING_GPL ChangeLog MANIFEST.in README build.py eggsetup.py setup.py docs/introduction.html docs/introduction.rst docs/running_perftest.txt docs/api/api-objects.txt docs/api/class-tree.html docs/api/crarr.png docs/api/epydoc.css docs/api/epydoc.js docs/api/frames.html docs/api/help.html docs/api/identifier-index.html docs/api/index.html docs/api/module-tree.html docs/api/redirect.html docs/api/toc-everything.html docs/api/toc-xappy-module.html docs/api/toc-xappy._checkxapian-module.html docs/api/toc-xappy.datastructures-module.html docs/api/toc-xappy.errors-module.html docs/api/toc-xappy.fieldactions-module.html docs/api/toc-xappy.fieldmappings-module.html docs/api/toc-xappy.highlight-module.html docs/api/toc-xappy.indexerconnection-module.html docs/api/toc-xappy.marshall-module.html docs/api/toc-xappy.memutils-module.html docs/api/toc-xappy.parsedate-module.html docs/api/toc-xappy.replaylog-module.html docs/api/toc-xappy.schema-module.html docs/api/toc-xappy.searchconnection-module.html docs/api/toc.html docs/api/xappy-module.html docs/api/xappy-pysrc.html docs/api/xappy._checkxapian-module.html docs/api/xappy._checkxapian-pysrc.html docs/api/xappy.datastructures-module.html docs/api/xappy.datastructures-pysrc.html docs/api/xappy.datastructures.Field-class.html docs/api/xappy.datastructures.ProcessedDocument-class.html docs/api/xappy.datastructures.UnprocessedDocument-class.html docs/api/xappy.errors-module.html docs/api/xappy.errors-pysrc.html docs/api/xappy.errors.IndexerError-class.html docs/api/xappy.errors.SearchEngineError-class.html docs/api/xappy.errors.SearchError-class.html docs/api/xappy.errors.XapianError-class.html docs/api/xappy.fieldactions-module.html docs/api/xappy.fieldactions-pysrc.html docs/api/xappy.fieldactions.ActionContext-class.html docs/api/xappy.fieldactions.FieldActions-class.html docs/api/xappy.fieldactions.SortableMarshaller-class.html docs/api/xappy.fieldmappings-module.html docs/api/xappy.fieldmappings-pysrc.html docs/api/xappy.fieldmappings.FieldMappings-class.html docs/api/xappy.highlight-module.html docs/api/xappy.highlight-pysrc.html docs/api/xappy.highlight.Highlighter-class.html docs/api/xappy.indexerconnection-module.html docs/api/xappy.indexerconnection-pysrc.html docs/api/xappy.indexerconnection.FacetQueryTypeIter-class.html docs/api/xappy.indexerconnection.IndexerConnection-class.html docs/api/xappy.indexerconnection.PrefixedTermIter-class.html docs/api/xappy.indexerconnection.SynonymIter-class.html docs/api/xappy.marshall-module.html docs/api/xappy.marshall-pysrc.html docs/api/xappy.memutils-module.html docs/api/xappy.memutils-pysrc.html docs/api/xappy.parsedate-module.html docs/api/xappy.parsedate-pysrc.html docs/api/xappy.replaylog-module.html docs/api/xappy.replaylog-pysrc.html docs/api/xappy.replaylog.LoggedProxy-class.html docs/api/xappy.replaylog.LoggedProxyMethod-class.html docs/api/xappy.replaylog.NotifyingDeleteObject-class.html docs/api/xappy.replaylog.ReplayLog-class.html docs/api/xappy.schema-module.html docs/api/xappy.schema-pysrc.html docs/api/xappy.schema.Schema-class.html docs/api/xappy.searchconnection-module.html docs/api/xappy.searchconnection-pysrc.html docs/api/xappy.searchconnection.SearchConnection-class.html docs/api/xappy.searchconnection.SearchConnection.ExpandDecider-class.html docs/api/xappy.searchconnection.SearchResult-class.html docs/api/xappy.searchconnection.SearchResultIter-class.html docs/api/xappy.searchconnection.SearchResults-class.html examples/fileindex.py examples/search.py libs/get_xapian.py perftest/analyse_indexlogs.py perftest/analyse_searchlogs.py perftest/gen_queries.py perftest/indexer.py perftest/parseargs.py perftest/perftest.py perftest/searcher.py perftest/setuppaths.py perftest/parse_wikipedia/Errors.py perftest/parse_wikipedia/HTMLUtils.py perftest/parse_wikipedia/XMLUtils.py perftest/parse_wikipedia/wiki2dump.py secore/__init__.py secore/datastructures.py secore/errors.py secore/fieldactions.py secore/fieldmappings.py secore/highlight.py secore/indexerconnection.py secore/marshall.py secore/parsedate.py secore/searchconnection.py testdata/query_sourcewords.txt testsuite/coverage.py testsuite/runtests.py testsuite/unittests/facet_hierarchy_1.py testsuite/unittests/facet_query_type_1.py testsuite/unittests/freetext_1.py testsuite/unittests/spell_correct_1.py utils/make_xappy_tarballs xappy/__init__.py xappy/_checkxapian.py xappy/datastructures.py xappy/datastructures_doctest1.txt xappy/errors.py xappy/errors_doctest1.txt xappy/fieldactions.py xappy/fieldmappings.py xappy/fieldmappings_doctest1.txt xappy/highlight.py xappy/highlight_doctest1.txt xappy/indexerconnection.py xappy/indexerconnection_doctest1.txt xappy/indexerconnection_doctest2.txt xappy/indexerconnection_doctest3.txt xappy/marshall.py xappy/marshall_doctest1.txt xappy/marshall_doctest2.txt xappy/memutils.py xappy/parsedate.py xappy/parsedate_doctest1.txt xappy/replaylog.py xappy/schema.py xappy/searchconnection.py xappy/searchconnection_doctest1.txt xappy/searchconnection_doctest2.txt xappy/searchconnection_doctest3.txt xappy.egg-info/PKG-INFO xappy.egg-info/SOURCES.txt xappy.egg-info/dependency_links.txt xappy.egg-info/top_level.txtxappy-0.5/xappy.egg-info/dependency_links.txt0000644000175000017500000000000111005556727021242 0ustar richardrichard xappy-0.5/xappy.egg-info/top_level.txt0000644000175000017500000000000611005556727017722 0ustar richardrichardxappy xappy-0.5/AUTHORS0000644000175000017500000000275110770032527013411 0ustar richardrichardAuthors ======= The Xappy module and accompanying documentation and testsuite (excluding coverage.py) is Copyright (C) 2007 Lemur Consulting Ltd. It is released under the GPL license; see the file COPYING_GPL in this directory for details. Major code and design --------------------- Richard Boulton (lead developer) Tom Mortimer (highlighting and summarisation) Tom Winch (facet heirarchy) Thanks are due to MyDeco (http://mydeco.com/) who have supported much of the development of Xappy. Bug reports and comments ------------------------ Thanks are due to the following individuals for helpful comments, bug reports and small patches: Bruno Rezende Third party code ---------------- The coverage.py file in the testsuite is Copyright 2001 Gareth Rees and Copyright 2004-2006 Ned Batchelder. See the end of that file for details of its licensing. Sample data ----------- The "testdata/query_sourcewords.txt" file contains a copy of /usr/share/dict/words from the "dictionaries-common" package in a Debian installation: Copyright (C) 1999-2003 Rafael Laboissiere Copyright (C) 2001-2004 Agustín Martín Domingo Copyright (C) 2003-2004 René Engelhard dictionaries-common is released under the terms of the GNU GPL, version 2, or at your option, any later version. (see /usr/share/common-licenses/GPL). "testdata/query_sourcewords.txt" also contains a copy of the text of John Milton's "Paradise Lost", taken from Project Gutenberg. xappy-0.5/COPYING_GPL0000644000175000017500000004310310667526240014077 0ustar richardrichard GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. xappy-0.5/ChangeLog0000644000175000017500000012457411005555653014125 0ustar richardrichardTue Apr 29 08:25:59 GMT 2008 Richard Boulton * MANIFEST.in,setup.py: Update setup.py and MANIFEST ready for 0.5 release. Tue Apr 29 07:58:10 GMT 2008 Richard Boulton * libs/get_xapian.py,utils/make_xappy_tarballs: Update scripts to get custom version of xapian to latest version. Mon Apr 28 23:25:46 GMT 2008 Richard Boulton * xappy/: Add check that xapian is at at least version 1.0.6; raise ImportError at import time if version is too old. Add checks for a version of xapian with sufficient features to support tags and facets, and disable those features if they're not present: an exception will be raised when tag or facet features are used if the xapian version is too old. Fri Apr 25 12:23:09 GMT 2008 Richard Boulton * testsuite/runtests.py: Copy fixes from xapian_1.0 branch to make the testsuite pass on windows. Thu Apr 17 23:07:35 GMT 2008 Richard Boulton * testsuite/unittests/freetext_1.py: New unit test for the search_by_default and allow_field_specific fields. Thu Apr 17 22:04:34 GMT 2008 Richard Boulton * docs/introduction.rst,xappy/fieldactions.py, xappy/searchconnection.py: Add allow_field_specific and search_by_default flags to INDEX_FREETEXT action. Sat Mar 29 16:59:23 GMT 2008 Richard Boulton * xappy/searchconnection.py: Fix some "foo if bar" constructions which broken python2.4. Should now work with python 2.4 again. Wed Mar 26 08:14:27 GMT 2008 Richard Boulton * xappy/fieldactions.py: Tidy up the imports in this file, too. Wed Mar 26 07:52:47 GMT 2008 Richard Boulton * xappy/__init__.py,xappy/datastructures.py, xappy/indexerconnection.py: Remove several "import *" lines from __init__.py, replacing them by importing the specific symbols desired. Remove the nasty renaming of imported symbols in the files thus imported, since this was to work around polluting the namespace when "import *" was used. Tue Mar 25 12:46:33 GMT 2008 Richard Boulton * testsuite/unittests/facet_query_type_1.py,xappy/indexerconnection.py, xappy/searchconnection.py: More facet selection improvements from Tom Winch: allow a set of associations between query types and facets to be stored in the database configuration, and use these facets to either prevent or prefer certain facets from being chosen for a particular query type. (Query types are specified by an additional parameter to the search() method.) Wed Mar 19 01:42:29 GMT 2008 Richard Boulton * xappy/indexerconnection.py,xappy/searchconnection.py: Remove backwards compatibility support for reading fieldactions from a file. It just makes the code more complex, and xappy really needs to use a more recent version of xapian. Tue Mar 18 21:34:29 GMT 2008 Richard Boulton * AUTHORS: Add Tom Winch. Tue Mar 18 21:29:25 GMT 2008 Richard Boulton * testsuite/unittests/facet_hierarchy_1.py,xappy/indexerconnection.py, xappy/searchconnection.py: Add support for defining a facet heirarchy, for use when selecting facets. Not yet used, but is stored in the database configuration, and available to both the indexer connection and the search connection. Mon Mar 17 16:46:33 GMT 2008 Richard Boulton * xappy/searchconnection.py: Fix setting of stemmer so that it still works with replaylog enabled. Thu Feb 21 13:12:03 GMT 2008 Richard Boulton * libs/get_xapian.py: Update to new tarballs which actually work, this time. Thu Feb 21 01:54:18 GMT 2008 Richard Boulton * libs/get_xapian.py: Revert to earlier tarballs - the new ones don't work. Thu Feb 21 01:50:17 GMT 2008 Richard Boulton * libs/get_xapian.py: Update with new tarballs. Thu Feb 21 01:23:46 GMT 2008 Richard Boulton * utils/make_xappy_tarballs: Update the branchpoint version numbers. Tue Feb 05 09:59:50 GMT 2008 Richard Boulton * libs/get_xapian.py: Upgrade version of xapian used to one which contains database replication functionality. Tue Feb 05 09:45:27 GMT 2008 Richard Boulton * xappy/indexerconnection.py,xappy/searchconnection.py, xappy/searchconnection_doctest3.txt: Add interface to IndexerConnection for setting and getting metadata, and interface to SearchConnection for getting metadata. Mon Feb 04 00:58:05 GMT 2008 Richard Boulton * xappy/searchconnection.py: Cope with a facet being declared as SORTABLE, but without a type, but of facet type float. (Treat the facet search as a numeric range, correctly - used to fail to serialise the numbers correctly.) * xappy/searchconnection_doctest2.txt: Add regression test. Sat Feb 02 17:59:24 GMT 2008 Richard Boulton * xappy/indexerconnection.py: Add simple work-around for synonyms - allow a field to be specified for the original word separately from the synonym. Needs tidying up, but allows slightly more flexibility in synonyms. * xappy/searchconnection_doctest2.txt: Adjust test accordingly. Sat Feb 02 13:14:29 GMT 2008 Richard Boulton * xappy/indexerconnection.py,xappy/searchconnection.py: Backwards compatibility fix for reading the metadata: if the config isn't in the metadata key, or metadata isn't supported by the version of xapian in use, read it from the file. When writing the config, if it can't be stored in the metadata, store it in a file. A database can now be upgraded to use the new metadata method simply by opening an indexerconnection on it, and then closing it. Sat Feb 02 12:47:33 GMT 2008 Richard Boulton * utils/make_xappy_tarballs: Tidy up tarball making script. Sat Feb 02 12:44:59 GMT 2008 Richard Boulton * xappy/searchconnection.py: Add faster implementation of expand decider, using a regexp for the prefixes. * xappy/searchconnection_doctest2.txt: Test it. Mon Jan 28 15:13:04 GMT 2008 Richard Boulton * xappy/indexerconnection.py,xappy/searchconnection.py: Change the storage of the settings from a file in the database directory to be in a metadata. This change allow the forthcoming replication support to copy databases without losing their settings, and should also be helpful when we implement remote database support. Wed Jan 23 22:27:50 GMT 2008 Richard Boulton * libs/get_xapian.py: Even newer xapian tarball - containing more fixes from charlie for windows. Wed Jan 23 16:04:12 GMT 2008 Richard Boulton * libs/get_xapian.py,utils/make_xappy_tarballs: Update xapian tarballs - mainly to get fixes for the build system on windows. Thu Jan 10 00:28:26 UTC 2008 Richard Boulton * libs/get_xapian.py: Update to get latest archives. Thu Jan 10 00:04:51 UTC 2008 Richard Boulton * utils/make_xappy_tarballs: Update with new branchpoint. Wed Jan 09 22:50:36 UTC 2008 Richard Boulton * utils/make_xappy_tarballs: Update with version numbers for latest branches. * libs/get_xapian.py: Update with details of latest tarballs, which include OP_VALUE_GE and OP_VALUE_LE. * xappy/searchconnection.py: Allow None to be specified as the begin or end or a range query - allows half ranges to be specified. * xappy/searchconnection_doctest2.txt: Test passing None as the end parameters of a range query. Wed Jan 09 22:46:31 GMT 2008 Richard Boulton * utils/make_xappy_tarballs: Update with version numbers for latest branches. * libs/get_xapian.py: Update with details of latest tarballs, which include OP_VALUE_GE and OP_VALUE_LE. * xappy/searchconnection.py: Allow None to be specified as the begin or end or a range query - allows half ranges to be specified. * xappy/searchconnection_doctest2.txt: Test passing None as the end parameters of a range query. Mon Jan 07 19:47:36 GMT 2008 Richard Boulton * libs/get_xapian.py: New script (taken from flax) to download the xapian tarballs and unpack them, ready to be built. * libs/*.tgz: Remove the tarballs from svn - they were too big to be kept here. They're now hosted on the googlecode download area, which should be as reliable as the googlecode svn server. * utils/make_xappy_tarballs: Update with new version numbers. Mon Jan 07 16:59:22 GMT 2008 Richard Boulton * utils/make_xappy_tarballs: Update version numbers for latest branch updates, to build new tarballs. Mon Dec 31 13:09:33 GMT 2007 Richard Boulton * xappy/searchconnection.py,xappy/searchconnection_doctest1.txt: Test opening of a database which doesn't exist, and set _index to None in class initialiser to avoid assertion error when calling close() from __del__() in this situation. Mon Dec 17 09:28:01 GMT 2007 Richard Boulton * xappy/searchconnection.py: Add _cluster method, and _reorder_by_clusters() method. Mon Dec 10 19:46:25 GMT 2007 Richard Boulton * utils/make_xappy_tarballs: Update to apply the changes in the clustering branch. Mon Dec 10 19:45:30 GMT 2007 Richard Boulton * xappy/searchconnection.py: Add ability to restrict the reordering to just use specific fields, and to use approximations for the termfreqs to speed it up. Mon Dec 10 17:19:34 GMT 2007 Richard Boulton * xappy/searchconnection.py: Remove accidentally committed debugging prints. Mon Dec 10 17:18:34 GMT 2007 Richard Boulton * xappy/searchconnection.py: Add (experimental) _reorder_by_similarity() method to SearchResults. Thu Dec 06 16:53:23 GMT 2007 Richard Boulton * xappy/searchconnection.py: Add a "userdata" parameter to the closehandler callback, to make writing the callbacks easier. * xappy/searchconnection_doctest2.txt: Test the userdata parameter. Thu Dec 06 12:27:53 GMT 2007 Richard Boulton * xappy/highlight_doctest1.txt: Don't display the output of the highlighter - we're just testing that it returns promptly. Thu Dec 06 12:19:55 UTC 2007 Tom Mortimer * xappy/highlight.py,xappy/highlight_doctest1.txt: Simplified regexp to work around freezing problem. Less procise now but probably good enough temporarily. Fixed test case. Thu Dec 06 07:38:49 GMT 2007 Richard Boulton * xappy/highlight_doctest1.txt: Add testcase of a pathological document for highlighting - the regular expression currently takes a ridiculously long time to process this. Thu Dec 06 07:29:28 GMT 2007 Richard Boulton * testsuite/runtests.py: Fix for running with debug logging. Wed Dec 05 15:57:41 GMT 2007 Richard Boulton * xappy/searchconnection.py: Improve a documentation comment. Mon Dec 03 18:01:51 GMT 2007 Richard Boulton * xappy/searchconnection.py,xappy/searchconnection_doctest2.txt: Add ability to set a callback on SearchConnection to be called when the object is closed (even if this is an implicit close due to being deleted). Thu Nov 29 17:58:18 GMT 2007 Richard Boulton * xappy/searchconnection.py: Expose an API for setting the minimum weight or percentage allowed for a result to be returned; this is done by supplying the percentcutoff or weightcutoff parameters to SearchConnection.search() * xappy/searchconnection_doctest2.txt: Test the weight and percentage cutoff parameters. Wed Nov 28 10:18:43 GMT 2007 Richard Boulton * xappy/searchconnection.py: Fix returning of empty facet value, which translates into numeric range from -inf to -inf: this is returned when some documents do not have an entry in a numeric range, with a count of the number of documents which matched but didn't have a numeric facet. Just ignore this information. Wed Nov 28 08:37:08 GMT 2007 Richard Boulton * xappy/searchconnection.py: Remove a typo. Wed Nov 28 08:15:09 GMT 2007 Richard Boulton * docs/introduction.rst,xappy/indexerconnection_doctest2.txt, xappy/searchconnection.py,xappy/searchconnection_doctest2.txt: Modify query parsing to ensure that exact matches are given a higher weight than stemmed or synonym matches. Update testcases accordingly. Wed Nov 28 07:34:21 GMT 2007 Richard Boulton * libs/: Update the xapian tarballs; these now include OP_SYNONYM and use it for synonym searches, wildcards, and partial searches. Tue Nov 27 22:39:54 GMT 2007 Richard Boulton * utils/make_xappy_tarballs: Add script to update the xappy tarballs from xapian SVN. Mon Nov 26 14:51:24 GMT 2007 Richard Boulton * testsuite/runtests.py: Call close methods on anything from xappy which has one when cleaning up. Mon Nov 26 14:11:46 GMT 2007 Richard Boulton * xappy/indexerconnection_doctest1.txt: Windows doesn't give a detail for why a DatabaseLockError can't be obtained, so make the test case more flexible there. Mon Nov 26 12:36:38 GMT 2007 Richard Boulton * testsuite/runtests.py: Delete entries in the dictionary before calling teardown; should help avoid trying to delete open files on windows. Sun Nov 18 15:45:26 GMT 2007 Richard Boulton * xappy/replaylog.py: New file - allows all calls to xapian to be logged, such that they could be replayed later for debugging. Has rather an unpleasant implementation, but as a result has minimal impact when not turned on - I've not been able to measure any performance impact incurred when not logging. * xappy/__init__.py: Expose new function "set_replay_path" used to start logging. * xappy/marshall.py, xappy/fieldactions.py, xappy/datastructures.py, xappy/indexerconnection.py, xappy/searchconnection.py: Hook into the replay logging. Sun Nov 18 15:44:50 GMT 2007 Richard Boulton * testsuite/runtests.py: Run without profiling by default - much faster. Thu Nov 15 08:38:18 GMT 2007 Richard Boulton * testsuite/runtests.py: Allow coverage and profiling measures to be turned on and off easily (not yet with command line options, but now only needs a simple edit to the code). Wed Nov 07 17:45:48 GMT 2007 Richard Boulton * xappy/searchconnection.py: Add extra "query" parameter to summarise() and highlight() methods, which can be used to override the query used as the basis of the highlighting. Wed Nov 07 17:30:02 GMT 2007 Richard Boulton * xappy/highlight.py: Fix tests to correspond to recent change. * xappy/searchconnection.py: Add "query_none()" to get an empty query explicitly. Can be useful as a placeholder. Tue Nov 06 13:54:13 UTC 2007 Tom Mortimer * xappy/highlight.py: Highlighter works with stemmed and unstemmed terms. Workaround until we have proper phrase highlighting Thu Nov 01 14:43:34 UTC 2007 Richard Boulton * libs/win32msvc.tgz: Updated build files for windows. Wed Oct 31 19:01:03 UTC 2007 Richard Boulton * libs/xapian-bindings-xappy.tgz: Version with a concurrency problem fixed. Wed Oct 31 17:57:00 UTC 2007 Richard Boulton * libs/matchspy.cc: Version of matchspy.cc with quick workaround to avoid segfault. Tue Oct 30 11:12:28 GMT 2007 Richard Boulton * xappy/searchconnection.py: Document the members of SearchResult. Tue Oct 30 11:02:22 GMT 2007 Richard Boulton * xappy/searchconnection.py: Add weight and percent members to SearchResult objects. Mon Oct 29 21:21:27 GMT 2007 Richard Boulton * README: Update to tell users to use the tarballs from the libs/ subdirectory. Mon Oct 29 21:19:01 GMT 2007 Richard Boulton * xappy/searchconnection.py,xappy/searchconnection_doctest2.txt: Fix setting of the prefix to use the correct form of add_prefix, and fix the expected output of scale weight queries to use the new style of output. Mon Oct 29 20:19:27 GMT 2007 Richard Boulton * libs/win32msvc.tgz,libs/xapian-bindings-xappy.tgz, libs/xapian-core-xappy.tgz: Add tarballs containing a suitable version of xapian to use with xappy. Mon Oct 29 15:07:00 GMT 2007 Richard Boulton * xappy/indexerconnection.py: Turn off the max_mem_use setting by default, so we don't mess up performance of existing applications. Mon Oct 29 14:59:26 GMT 2007 Richard Boulton * xappy/indexerconnection.py: Increase estimate of amount of memory used, based on profiling observations. Mon Oct 29 14:14:04 GMT 2007 Richard Boulton * testsuite/unittests/spell_correct_1.py: Add unittest demonstrating problem with spelling correction. Mon Oct 29 14:08:59 GMT 2007 Richard Boulton * xappy/memutils.py: New file, which gets the total amount of physical memory on the system (for windows and POSIX). * xappy/indexerconnection.py: Add set_max_mem_use(), which causes an automatic flush if more than a certain (configurable) amount of memory is used. This should help to avoid using all the memory for buffered changes, resulting in swapping. The estimate of the memory used is fairly primitive, though, so could do with improvment. Mon Oct 29 09:30:21 GMT 2007 Richard Boulton * xappy/searchconnection.py: Retry parse_query() attempt without support for boolean operators if it fails in spell correct routine, to match behaviour of query_parse() routine. Fri Oct 12 09:52:31 BST 2007 Richard Boulton * xappy/searchconnection.py: If allow, deny, default_deny or default_allow are passed as empty lists, behave as if they were passed as None. Wed Oct 10 22:56:19 BST 2007 Richard Boulton * xappy/searchconnection.py: Update some documentation comments. Wed Oct 10 18:21:33 BST 2007 Richard Boulton * xappy/searchconnection.py: Add the default_op, default_allow, and default_deny optional parameters to spell_correct(), so that it takes the same arguments as query_parse(). Wed Oct 10 01:25:01 BST 2007 Richard Boulton * perftest/perftest.py: Remove facet and tags test runs - we don't have the data needed to make them run, anyway. Wed Oct 10 01:22:20 BST 2007 Richard Boulton * perftest/perftest.py,perftest/searcher.py: Add use_or option to search runs, and do an "OR" run by default. Tue Oct 09 16:03:42 BST 2007 Richard Boulton * xappy/searchconnection.py: Expand documentation comment to explain the distinction between default_{allow,deny} and {allow,deny}. Tue Oct 09 15:36:32 BST 2007 Richard Boulton * perftest/perftest.py: Add "--usedb" parameter - if supplied, a ready made DB is assumed to be at that path, and no index run will be done. Tue Oct 09 15:10:00 BST 2007 Richard Boulton * perftest/perftest.py: If pylab isn't available, don't call the analyse_* functions (and don't produce pretty graphs, as a result). Tue Oct 09 14:55:53 BST 2007 Richard Boulton * README,docs/introduction.rst: Update comments about the version of Xapian which is required. Tue Oct 09 02:14:24 BST 2007 Richard Boulton * docs/running_perftest.txt: More instructions. Tue Oct 09 02:05:03 BST 2007 Richard Boulton * docs/running_perftest.txt: Add some notes on running the performance tests, with wikipedia data. Tue Oct 09 01:48:58 BST 2007 Richard Boulton * perftest/perftest.py: More tidying, ready for running big tests against wikipedia. Tue Oct 09 01:32:43 BST 2007 Richard Boulton * perftest/searcher.py: Tidy up headings. Tue Oct 09 01:21:38 BST 2007 Richard Boulton * perftest/: Sort out search side of performance tests. Mon Oct 08 23:46:18 BST 2007 Richard Boulton * perftest/: Tidy up, towards making automated performance tests runnable just by running a single script. Fix graph drawing for cases where there are few sample points. Mon Oct 08 14:22:25 BST 2007 Richard Boulton * AUTHORS: Add second name for Bruno Rezende. Sun Oct 07 01:56:47 BST 2007 Richard Boulton * xappy/searchconnection.py: Change from using OP_MULT_WEIGHT to use OP_SCALE_WEIGHT, to work with latest version of xapian. Sat Oct 06 01:55:34 BST 2007 Richard Boulton * MANIFEST.in,eggsetup.py,setup.py: Basic start of distutils packaging. Wed Oct 03 14:00:17 BST 2007 Richard Boulton * build.py: Don't include private variables in the output of epydoc; this makes it more useful as an API reference. * docs/introduction.rst: Add a note on error handling. Wed Oct 03 13:04:01 BST 2007 Richard Boulton * xappy/errors.py,xappy/errors_doctest1.txt: Export all the xapian error types (eg, xapian.FooError) as xappy.XapianFooError. Also, make them all subclasses of xappy.XapianError. This allow a particular Xapian error to be caught using "except xappy.XapianFooError", or all Xapian errors to be caught using "except xappy.XapianError". Wed Oct 03 12:36:27 BST 2007 Richard Boulton * xappy/highlight.py,xappy/searchconnection_doctest3.txt: Fix from Alex Bowley to coerce maxlen into an int in highlight.py Tue Oct 02 18:31:54 BST 2007 Richard Boulton * xappy/searchconnection.py: Minor correction to a documentation comment. Tue Oct 02 18:03:31 BST 2007 Richard Boulton * xappy/searchconnection.py: Add query_adjust(), allowing the weights of one query to be adjusted based on the results of a second query. * xappy/searchconnection_doctest2.txt: Add test for query_adjust() Mon Oct 01 15:23:11 BST 2007 Richard Boulton * xappy/searchconnection.py: Add a __len__() method for SearchResults(). * xappy/searchconnection_doctest1.txt, xappy/searchconnection_doctest2.txt: Test it Mon Oct 01 14:23:22 BST 2007 Richard Boulton * xappy/searchconnection.py: Add SearchConnection.query_multweight, which produces a query from a subquery by multiplying the weights by a multiplier. * xappy/indexerconnection_doctest2.txt: Modify test of "Cannot specify both `allow` and `deny`" to expect new extended message. * xappy/searchconnection_doctest2.txt: Add test of a multweight query. Sun Sep 30 10:37:21 BST 2007 Richard Boulton * xappy/searchconnection.py,xappy/searchconnection_doctest2.txt: Add "required_facets" parameter to get_suggested_facets(), allowing certain facets to be required in the list of returned facets. Fri Sep 28 16:12:35 BST 2007 Richard Boulton * testsuite/coverage.py: Update copy of coverage.py to latest version (with patches applied) to get correct results with python2.5 Mon Sep 24 14:21:48 BST 2007 Richard Boulton * xappy/searchconnection.py,xappy/searchconnection_doctest2.txt: Add default_allow and default_deny parameters to query_parse. These allow a list of field names to be specified which will be searched by default (instead of searching all free-text fields). Needs latest SVN version of xapian. Sat Sep 22 09:21:13 BST 2007 Richard Boulton * xappy/searchconnection.py: Add 'rb' to another call to open that I missed. Thu Sep 20 15:20:41 BST 2007 Richard Boulton * AUTHORS: Start list of individuals who have contributed in any way. Tue Sep 18 13:23:15 BST 2007 Richard Boulton * xappy/datastructures.py,xappy/indexerconnection_doctest1.txt: Document, and test, that it's okay to use an iterator for UnprocessedDocument.fields. Tue Sep 18 13:05:53 BST 2007 Richard Boulton * docs/introduction.rst: Clarify some of the documentation about facets. Fri Sep 07 16:51:33 BST 2007 Richard Boulton * ChangeLog: Tidy-up whitespace. Wed Sep 05 15:33:27 BST 2007 Richard Boulton * examples/fileindex.py,examples/search.py,perftest/index_from_dump.py, perftest/search_speed.py: Change all remaining references to "secore" name, except in the compatibility wrapper and the tests for that, to "xappy". Wed Sep 05 15:29:22 BST 2007 Richard Boulton * docs/introduction.rst: Change references to secore to references to xappy. * xappy/fieldmappings_doctest1.txt: Add test which I wrote ages ago, but had forgotten to commit. Wed Sep 05 15:05:57 BST 2007 Richard Boulton * secore/,testsuite/runtests.py: Add compatibility layer so that old scripts can run without needing to change from "secore" to "xappy", for now. Change testsuite to run using new names (but use the old ones too, to test the compatibility layer). Wed Sep 05 14:24:52 BST 2007 Richard Boulton * AUTHORS,README,build.py,secore/,xappy/__init__.py: Rename secore to xappy. Adjust accompanying scripts and documentation accordingly. Wed Sep 05 02:23:46 BST 2007 Richard Boulton * secore/searchconnection_doctest2.txt: Change expected output to match output given by xapian SVN HEAD, once the bug in check_at_least is resolved. Fri Aug 17 14:41:13 BST 2007 Richard Boulton * perftest/index_from_dump.py: Remove pointless "os.stat" Fri Aug 17 14:38:46 BST 2007 Richard Boulton * secore/indexerconnection.py: Add a method to get a list of the fields which have actions defined. Thu Aug 16 17:42:30 BST 2007 Richard Boulton * secore/indexerconnection.py: Add a check for the database not having been closed. * secore/searchconnection.py: Add method for getting an iterator over all the documents in the database. Add support for rerunning the attempted access if get_document() catches a DatabaseModifiedError. * secore/searchconnection_doctest2.txt: Change "get_significant_terms" to "significant_terms()", and test it. Thu Aug 16 17:24:06 BST 2007 Richard Boulton * secore/searchconnection.py,secore/searchconnection_doctest2.txt: Add new method "get_significant_terms()" which returns the most significant terms in the set of ids specified. Thu Aug 16 10:22:16 BST 2007 Richard Boulton * secore/searchconnection_doctest2.txt: Add test for supplying a document ID to query_similar() which isn't in the database. Thu Aug 16 09:49:09 BST 2007 Richard Boulton * docs/introduction.rst: Add documentation for similarity search. Thu Aug 16 09:15:44 BST 2007 Richard Boulton * secore/searchconnection.py: Retry the expand until we don't get a DatabaseModifiedError. Thu Aug 16 09:06:44 BST 2007 Richard Boulton * secore/searchconnection.py,secore/searchconnection_doctest2.txt: Implementation of the query_similar() method, returning a query to use to get a new set of results based on similarity. Wed Aug 08 18:52:24 BST 2007 Richard Boulton * secore/searchconnection.py,secore/searchconnection_doctest2.txt: Add API for performing searches for similar documents. Currently just works out which fields should be used for performing the similarity comparison, but doesn't do the actual similarity search. Wed Aug 08 13:37:26 BST 2007 Richard Boulton * secore/searchconnection.py: Fix up calculation of significant digits to cope with extreme values (ie, 0), to round to the nearest significant digit (previously, it rounded down), and to use math.log10 instead of a loop to calculate the logarithm. Wed Aug 08 13:21:41 BST 2007 Richard Boulton * secore/searchconnection.py: Fix issue with new match estimate rounding when match estimate is 0. Wed Aug 08 03:17:37 BST 2007 Richard Boulton * secore/searchconnection.py: Improve documentation comment. Wed Aug 08 03:13:10 BST 2007 Richard Boulton * secore/searchconnection.py: Add "matches_human_readable_estimate" to search results - returns an estimate of the number of matching documents, rounded according to how tight the upper and lower bounds are. Sat Aug 04 08:16:01 BST 2007 Richard Boulton * secore/searchconnection.py: Add convenience methods for checking if a particular field can be collapsed or sorted on. Sat Aug 04 03:09:32 BST 2007 Richard Boulton * docs/introduction.rst,secore/: Reorganise field structures, allowing us to support multiple occurrences of facets of string type for a single document. This change requires all databases to be rebuilt. Tests updated accoringly. Also, requires latest SVN HEAD build of xapian. Wed Aug 01 14:45:41 BST 2007 Richard Boulton * secore/searchconnection_doctest2.txt: Test for multiple facet values in a single document (currently fails, due to this not being supported correctly yet) Wed Aug 01 14:23:24 BST 2007 Richard Boulton * secore/searchconnection_doctest2.txt: More tests, including a regression test for bug with facet calculation on database with no facet fields defined. Wed Aug 01 12:43:57 BST 2007 Richard Boulton * secore/searchconnection_doctest2.txt: Improve test coverage. Wed Aug 01 12:28:48 BST 2007 Richard Boulton * secore/searchconnection.py: Fix bug when facet calculation is requested, but no facet fields are present in the database (used to throw an exception when the list of suggested facets was requested in this case - now it just returns an empty list). Tue Jul 31 08:34:49 BST 2007 Richard Boulton * secore/indexerconnection_doctest2.txt,secore/searchconnection.py, secore/searchconnection_doctest3.txt: Improve test coverage - in particular, add tests of various conditions which cause errors. Mon Jul 30 16:10:52 BST 2007 Richard Boulton * secore/datastructures.py,secore/datastructures_doctest1.txt: Add test for terms which are too long, and note in the code about why this restriction exists, and how it could be removed. Mon Jul 30 14:29:51 BST 2007 Richard Boulton * docs/introduction.rst: Update test for displaying a facet range. Mon Jul 30 14:29:08 BST 2007 Richard Boulton * secore/searchconnection.py: Update documentation comment for query_facet() method. Mon Jul 30 12:38:25 BST 2007 Richard Boulton * secore/searchconnection.py: Fix bug with handling of facets of type 'float'. Fri Jul 27 02:04:27 BST 2007 Richard Boulton * secore/fieldactions.py,secore/searchconnection.py: Add facet searching. Fri Jul 27 01:13:27 BST 2007 Richard Boulton * secore/searchconnection.py: For facet selection - don't return facets which only have 1 or 0 values. Thu Jul 26 17:02:33 BST 2007 Richard Boulton * secore/datastructures.py: Warn early if a field is too long: we might be able to replace this by hashing if necessary, but this is better than waiting for the xapian error in this case. Wed Jul 25 08:37:51 BST 2007 Richard Boulton * docs/introduction.rst: Add documentation on indexing and searching facets. Wed Jul 25 03:06:19 BST 2007 Richard Boulton * secore/searchconnection.py: Correct small initialisation bug. Wed Jul 25 01:53:51 BST 2007 Richard Boulton * secore/: Change string marshalling to use xapian's stuff; cuts down code, uses a more compact representation, and is compatible with the facet range calculation stuff. Update tests to cover the facet calculation stuff in more detail (but still need more coverage). Fix bug with converting string range to a numeric range more than once if get_suggested_facets is called repeatedly. Tue Jul 24 10:32:56 BST 2007 Richard Boulton * secore/fieldactions.py,secore/searchconnection.py, secore/searchconnection_doctest2.txt: Add the "FACET" action, to store facets for field search and facet selection. Still remaining is to change the serialisation of floats to match Xapian to make the numeric range calculation work correctly, translate the resulting numeric ranges into a more suitable python representation, and handle multiple values for a particular facet being specified for a single document. Mon Jul 23 10:59:58 BST 2007 Richard Boulton * docs/introduction.rst,secore/searchconnection.py: Add special value of -1 for checkatleast parameter, to check all matches, and document it (and the general reason for setting the checkatleast parameter when using get_top_tags()). Mon Jul 23 10:40:22 BST 2007 Richard Boulton * secore/: Add missing synonym stuff. Tue Jul 17 13:42:39 BST 2007 Richard Boulton * docs/introduction.rst,secore/fieldactions.py, secore/searchconnection.py: Add some documentation of tags, and fix a couple of bugs. Tue Jul 17 13:25:10 BST 2007 Richard Boulton * secore/fieldactions.py,secore/searchconnection.py: Add support for tagging - as yet, undocumented, and minimally tested. Mon Jul 16 11:32:18 BST 2007 Richard Boulton * secore/searchconnection.py: Check for KeyError when getting a slot number for a range restriction, too. Mon Jul 16 11:18:36 BST 2007 Richard Boulton * secore/searchconnection.py: Check for KeyError when accessing list of field actions, and behave as if an empty list was found if the field is unknown. Fri Jul 13 16:39:50 BST 2007 Richard Boulton * secore/searchconnection.py: Add an option to query_filter to return only those documents which _don't_ match the filter, instead of those which do. * secore/searchconnection_doctest2.txt: Add a test for using a filter with exclude=True. Mon Jul 09 11:23:56 BST 2007 Richard Boulton * secore/searchconnection.py: Convert supplied sequence of queries to list, since xapian query constructor isn't happy to take an iterator. Fri Jul 06 16:38:11 BST 2007 Richard Boulton * secore/indexerconnection.py: Fix bug in replace() causing the document data not to be stored. Wed Jul 04 17:24:40 BST 2007 Richard Boulton * docs/introduction.rst,perftest/index_from_dump.py,secore/: Change all occurrences of unique_id to just "id" - no need to say the unique bit, so it's just wasted typing. Mon Jul 02 09:08:39 BST 2007 Richard Boulton * secore/searchconnection.py: If a search connection is opened before the fieldmappings file has been created, give it an empty FieldMappings object. Also, fix a bug in handling of checkatleast. Sun Jul 01 18:13:34 BST 2007 Richard Boulton * secore/searchconnection.py: Add query_all(), to make a search matching all documents in the database. Fri Jun 29 09:36:49 BST 2007 Richard Boulton * secore/searchconnection.py: Encode correctly spelt queries in UTF8, for consistency with output of Xapian. * secore/searchconnection_doctest2.txt: Test spelling correction with unicode strings. Fri Jun 29 09:00:14 BST 2007 Richard Boulton * secore/indexerconnection_doctest3.txt, secore/searchconnection_doctest2.txt: Improve test coverage. Fri Jun 29 08:47:34 BST 2007 Richard Boulton * docs/introduction.rst,secore/: Finally, properly implement and document the spelling correction support. Thu Jun 28 23:33:06 BST 2007 Richard Boulton * docs/introduction.rst: Fix documentation of parameters to INDEX_FREETEXT, and adjust an example to give expected output after recent fix to highlighting. * secore/fieldactions.py: Add an option allowing indexing without positional information, and an option allowing indexing with spelling correction. * secore/highlight.py,secore/searchconnection_doctest1.txt: Update output of examples to match recent fix to highlighting. Thu Jun 28 15:26:36 BST 2007 Tom Mortimer * secore/fieldactions.py: Add stopwording, and an option not to store prefixed terms, to freetext indexing. * secore/highlight.py: Fix a bug causing the requested maxlength to be exceeded if the derived blocks were too big. Fri Jun 08 15:37:21 BST 2007 Richard Boulton * AUTHORS,testdata/query_sourcewords.txt: Add source words for generating queries to test with, and list the copyright holders in AUTHORS. * perftest/: Add some routines for performing performance tests, and analysing the logs of these tests. * perftest/parse_wikipedia/: Add some routines which convert XML dumps of wikipedia data into scriptindex compatible forms. Fri Jun 08 11:58:54 BST 2007 Richard Boulton * Initial import into code.google.com repository. Wed May 16 20:03:02 BST 2007 Richard Boulton * Remove textprocessor.py in favour of using the new TermGenerator stuff in Xapian 1.0.0. Implement sorting by date or floating point. Add query_range() method for searching all documents in a given range. Wed May 16 15:44:18 BST 2007 Richard Boulton * README: Add a note on the name, and list docutils as a dependency. Wed May 16 10:27:22 BST 2007 Richard Boulton * secore/indexerconnection.py: Add get_document() method, to get a document given it's unique ID. Fri Apr 27 18:34:25 BST 2007 Richard Boulton * README: Adjust some paths. Fri Apr 27 18:22:19 BST 2007 Richard Boulton * docs/introduction.rst: Finish documentation by documenting collapse. Fri Apr 27 18:17:41 BST 2007 Richard Boulton * docs/introduction.rst: And the section of sorting is done. Fri Apr 27 18:00:32 BST 2007 Richard Boulton * docs/introduction.rst: Finished section on searching, apart from bits on sorting and collapsing. Fri Apr 27 17:11:16 BST 2007 Richard Boulton * docs/introduction.rst: Finished section on indexing. Fri Apr 27 16:41:23 BST 2007 Richard Boulton * build.py: Change method of calling rst2html and epydoc to avoid using system, and hopefully be cross-platform. Fri Apr 27 16:05:44 BST 2007 Richard Boulton * AUTHORS,COPYING_GPL: Add files listing authors, copyrights and license. Fri Apr 27 16:00:08 BST 2007 Richard Boulton * build.py,secore/__init__.py,testsuite/runtests.py: Fix headers to contain licenses and appropriate comments. Fri Apr 27 15:50:50 BST 2007 Richard Boulton * README,build.py,docs/makedocs.py: Move makedocs.py to build.py, and add documentation on the prerequisites needed. Fri Apr 27 15:16:34 BST 2007 Richard Boulton * README,docs/introduction.rst: Move details of how to run testsuite from README into new file, together with basic introduction to secore. (Sections which need finishing are marked with FIXME.) * docs/makedocs.py: Add script which makes all the documentation. * testsuite/runtests.py: Add ability to test doctests in external documentation, and add 'docs/introduction.rst' to the tests. Fri Apr 27 14:14:58 BST 2007 Richard Boulton * README: Add a basic README to point users to the appropriate documentation. Fri Apr 27 13:16:45 BST 2007 Richard Boulton * coverage.py,runtests.py,testsuite/runtests.py: Move the testsuite into a subdirectory, to tidy up the top level. Fri Apr 27 12:45:18 BST 2007 Richard Boulton * secore/datastructures.py,secore/errors.py: Fixes to documentation comments to make epydoc happier. Fri Apr 27 12:37:29 BST 2007 Richard Boulton * ChangeLog: Added new file, to keep track of changes. Current project status: - Basic API complete and implemented. - Tests cover all lines of code, apart from TextProcessor, which is scheduled for removal soon anyway. xappy-0.5/MANIFEST.in0000644000175000017500000000027511005555574014102 0ustar richardrichardinclude MANIFEST.in include ChangeLog include README include setup.py include eggsetup.py include xappy/*.py include docs/api/* include docs/introduction.html include docs/introduction.rst xappy-0.5/README0000644000175000017500000000302410711447317013215 0ustar richardrichardREADME ====== Xappy provides a simple-to-use interface to a search engine (Xapian - http://xapian.org/). For an introduction to the "xappy" module, read the documentation in "docs/introduction.html". (If you have an SVN checkout, you may need to generate this documentation by running "./build.py") You can run the testsuite by running "./testsuite/runtests.py". All changes are logged in the ChangeLog. Prerequisites ------------- - Python. Version 2.4 or 2.5 should be suitable. Earlier versions may not work correctly, and versions earlier than 2.2 will certainly not work (since they are not supported by Xapian). - Xapian (core library and python bindings). Currently, no release contains all the features needed for Xappy: you will need a snapshot release of Xapian. Appropriate snapshots are available from the tarballs in the libs/ subdirectory: we do not currently support use of a version of Xapian other than that in those tarballs. - rst2html and epydoc. These are used to format the documentation - you should be able to use the "xappy" module without them, but it won't be so easy to know _how_ to use it! - Python docutils. This is needed for generating the documentation - most Python installations will already have docutils included, but you may need to install it specifically in some cases. Building -------- The xappy module is pure Python, and thus doesn't really need to be built. However, there is a "build.py" script at the top level of the project - this will generate all the documentation. xappy-0.5/build.py0000755000175000017500000000322710700711050014000 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. r"""build.py: Build the documentation for Xappy. """ __docformat__ = "restructuredtext en" import os import sys # Set the locale, if possible, so rst2html doesn't produce localised output. try: import locale locale.setlocale(locale.LC_ALL, '') except: pass from docutils.core import publish_cmdline, default_description import epydoc.cli def call_rst2html(*args): description = ('Generates (X)HTML documents from standalone reStructuredText ' 'sources. ' + default_description) args = list(args) publish_cmdline(writer_name='html', description=description, argv=args) def call_epydoc(*args): args = list(args) args.insert(0, 'epydoc') sys.argv = args epydoc.cli.cli() call_rst2html('docs/introduction.rst', 'docs/introduction.html') call_rst2html('README', 'README.html') call_epydoc('-o', 'docs/api', '--name', 'xappy', '--no-private', 'xappy') xappy-0.5/eggsetup.py0000755000175000017500000000206510702027402014526 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Setup script for xappy using setuptools. This is actually a wrapper for the standard setup.py script, which causes it to use setuptools. This allows extended commands to be used - in particular, "test" to run the testsuite, and "bdist_egg" to build eggs. """ import setuptools execfile('setup.py') xappy-0.5/setup.py0000755000175000017500000001100111005556713014042 0ustar richardrichard#!/usr/bin/env python # # Copyright (C) 2007 Lemur Consulting Ltd # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """Setup script for xappy extension module. """ import sys # Use setuptools if we're part of a larger build system which is already using # it. if ('setuptools' in sys.modules): import setuptools from setuptools import setup, Extension from setuptools.command.build_ext import build_ext using_setuptools = True else: import distutils from distutils.core import setup, Extension from distutils import sysconfig using_setuptools = False # Customise compiler options. if using_setuptools: try: setuptools_build_ext = build_ext.build_extension def my_build_ext(self, ext): """Remove the -Wstrict-prototypes option from the compiler command. This option isn't supported for C++, so we remove it to avoid annoying warnings. """ try: self.compiler.compiler_so.remove('-Wstrict-prototypes') except (AttributeError, ValueError): pass retval = setuptools_build_ext(self, ext) return retval build_ext.build_extension = my_build_ext except AttributeError: pass else: distutils_customize_compiler = sysconfig.customize_compiler def my_customize_compiler(compiler): """Remove the -Wstrict-prototypes option from the compiler command. This option isn't supported for C++, so we remove it to avoid annoying warnings. """ retval = distutils_customize_compiler(compiler) try: compiler.compiler_so.remove('-Wstrict-prototypes') except (AttributeError, ValueError): pass return retval sysconfig.customize_compiler = my_customize_compiler # Extra arguments for setup() which we don't always want to supply. extra_kwargs = {} if using_setuptools: extra_kwargs['test_suite'] = "test.test" # FIXME long_description = """ The "xappy" python module is an easy-to-use interface to the Xapian search engine. Xapian provides a low level interface, dealing with terms and documents, but not really worrying about where terms come from, or how to build searches to match the way in which data has been indexed. In contrast, "xappy" allows you to design a field structure, specifying what kind of information is held in particular fields, and then uses this field structure to index data appropriately, and to build and perform searches. Xappy is not yet stable - in particular, both the API and database format will change in future releases. If you wish to use it, we recommend that you subscribe to the xappy-discuss mailing list (see http://groups.google.com/group/xappy-discuss) to keep up-to-date with changes to Xappy. """ setup(name = "xappy", version = "0.5", # update this in xappy/__init__.py, too. FIXME - get automatically author = "Richard Boulton", author_email = "richard@lemurconsulting.com", maintainer = "Richard Boulton", maintainer_email = "richard@lemurconsulting.com", url = "http://code.google.com/p/xappy", download_url = "http://xappy.googlecode.com/files/xappy-0.5.tar.gz", description = "Easy-to-use interface to the Xapian search engine", long_description = long_description, classifiers = [ 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Programming Language :: C++', 'Topic :: Internet :: WWW/HTTP :: Indexing/Search', 'Operating System :: MacOS', 'Operating System :: Microsoft', 'Operating System :: POSIX', ], license = 'GPL', platforms = 'Any', packages = ['xappy'], package_dir = {'xappy': 'xappy'}, **extra_kwargs) xappy-0.5/PKG-INFO0000644000175000017500000000312511005556727013437 0ustar richardrichardMetadata-Version: 1.0 Name: xappy Version: 0.5 Summary: Easy-to-use interface to the Xapian search engine Home-page: http://code.google.com/p/xappy Author: Richard Boulton Author-email: richard@lemurconsulting.com License: GPL Download-URL: http://xappy.googlecode.com/files/xappy-0.5.tar.gz Description: The "xappy" python module is an easy-to-use interface to the Xapian search engine. Xapian provides a low level interface, dealing with terms and documents, but not really worrying about where terms come from, or how to build searches to match the way in which data has been indexed. In contrast, "xappy" allows you to design a field structure, specifying what kind of information is held in particular fields, and then uses this field structure to index data appropriately, and to build and perform searches. Xappy is not yet stable - in particular, both the API and database format will change in future releases. If you wish to use it, we recommend that you subscribe to the xappy-discuss mailing list (see http://groups.google.com/group/xappy-discuss) to keep up-to-date with changes to Xappy. Platform: Any Classifier: Development Status :: 3 - Alpha Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Programming Language :: C++ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search Classifier: Operating System :: MacOS Classifier: Operating System :: Microsoft Classifier: Operating System :: POSIX xappy-0.5/setup.cfg0000644000175000017500000000007311005556727014162 0ustar richardrichard[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0