From fa77a949aa9cef002b24659532ec6a4ef140e2ca Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Mon, 29 Jul 2024 14:58:39 +0200 Subject: [PATCH 01/26] Log error from main using tracing --- meilisearch/src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/meilisearch/src/main.rs b/meilisearch/src/main.rs index e881734fb..2e70b4eb7 100644 --- a/meilisearch/src/main.rs +++ b/meilisearch/src/main.rs @@ -72,6 +72,19 @@ fn on_panic(info: &std::panic::PanicInfo) { #[actix_web::main] async fn main() -> anyhow::Result<()> { + try_main().await.inspect_err(|error| { + tracing::error!(%error); + let mut current = error.source(); + let mut depth = 0; + while let Some(source) = current { + tracing::info!(%source, depth, "Error caused by"); + current = source.source(); + depth += 1; + } + }) +} + +async fn try_main() -> anyhow::Result<()> { let (opt, config_read_from) = Opt::try_build()?; std::panic::set_hook(Box::new(on_panic)); From 9719dec443a02958dcd7e22d13bb881d028dad00 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Mon, 29 Jul 2024 16:19:35 +0200 Subject: [PATCH 02/26] Attach declared attributes-localized subroutes --- meilisearch/src/routes/indexes/settings.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/meilisearch/src/routes/indexes/settings.rs b/meilisearch/src/routes/indexes/settings.rs index 6f081f1c7..e95a75f69 100644 --- a/meilisearch/src/routes/indexes/settings.rs +++ b/meilisearch/src/routes/indexes/settings.rs @@ -682,6 +682,7 @@ generate_configure!( filterable_attributes, sortable_attributes, displayed_attributes, + localized_attributes, searchable_attributes, distinct_attribute, proximity_precision, From b1b3a1a98b7ffe0e742cb578f47eb95e17e75bd6 Mon Sep 17 00:00:00 2001 From: Tamo Date: Tue, 30 Jul 2024 15:51:02 +0200 Subject: [PATCH 03/26] add a get, set and put test for the localized attributes setting --- meilisearch/tests/settings/get_settings.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/meilisearch/tests/settings/get_settings.rs b/meilisearch/tests/settings/get_settings.rs index 58805d54f..1571b8ca6 100644 --- a/meilisearch/tests/settings/get_settings.rs +++ b/meilisearch/tests/settings/get_settings.rs @@ -9,6 +9,7 @@ static DEFAULT_SETTINGS_VALUES: Lazy> = Lazy::new(| let mut map = HashMap::new(); map.insert("displayed_attributes", json!(["*"])); map.insert("searchable_attributes", json!(["*"])); + map.insert("localized_attributes", json!(null)); map.insert("filterable_attributes", json!([])); map.insert("distinct_attribute", json!(null)); map.insert( @@ -409,6 +410,7 @@ macro_rules! test_setting_routes { test_setting_routes!( filterable_attributes put, displayed_attributes put, + localized_attributes put, searchable_attributes put, distinct_attribute put, stop_words put, From 8acd3f50bb224d2804616db975fd5b55f66ed5da Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 09:53:00 +0200 Subject: [PATCH 04/26] skip normalization when the locales and values are the same --- .../extract/extract_facet_string_docids.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs index 6452a67a1..f1ac07deb 100644 --- a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs +++ b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs @@ -68,10 +68,18 @@ pub fn extract_facet_string_docids( // Facet search normalization { - let locales = settings_diff.old.localized_faceted_fields_ids.locales(field_id); - let old_hyper_normalized_value = normalize_facet_string(normalized_value, locales); - let locales = settings_diff.new.localized_faceted_fields_ids.locales(field_id); - let new_hyper_normalized_value = normalize_facet_string(normalized_value, locales); + let old_locales = settings_diff.old.localized_faceted_fields_ids.locales(field_id); + let new_locales = settings_diff.new.localized_faceted_fields_ids.locales(field_id); + + if is_same_value && old_locales == new_locales { + // optimization: skip costly normalizations if the values and locales stayed the same + // TODO: splitting the cases between a settings diff and a document update would possibly allow for more optimizations, + // such as skipping the locales check when doing a documents update. + continue; + } + + let old_hyper_normalized_value = normalize_facet_string(normalized_value, old_locales); + let new_hyper_normalized_value = normalize_facet_string(normalized_value, new_locales); let set = BTreeSet::from_iter(std::iter::once(normalized_value)); From 7c3fc8c6555df60199026fa6873caf705320909b Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 10:57:46 +0200 Subject: [PATCH 05/26] Split settings and document facet string extractions --- .../extract/extract_facet_string_docids.rs | 138 ++++++++++++++++-- 1 file changed, 126 insertions(+), 12 deletions(-) diff --git a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs index f1ac07deb..fd5949fd9 100644 --- a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs +++ b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs @@ -12,6 +12,7 @@ use heed::BytesEncode; use super::helpers::{create_sorter, sorter_into_reader, try_split_array_at, GrenadParameters}; use crate::heed_codec::facet::{FacetGroupKey, FacetGroupKeyCodec}; use crate::heed_codec::{BEU16StrCodec, StrRefCodec}; +use crate::localized_attributes_rules::LocalizedFieldIds; use crate::update::del_add::{DelAdd, KvReaderDelAdd, KvWriterDelAdd}; use crate::update::index_documents::helpers::{ merge_deladd_btreeset_string, merge_deladd_cbo_roaring_bitmaps, @@ -28,6 +29,116 @@ pub fn extract_facet_string_docids( docid_fid_facet_string: grenad::Reader, indexer: GrenadParameters, settings_diff: &InnerIndexSettingsDiff, +) -> Result<(grenad::Reader>, grenad::Reader>)> { + if settings_diff.settings_update_only() { + extract_facet_string_docids_settings(docid_fid_facet_string, indexer, settings_diff) + } else { + let localized_field_ids = &settings_diff.new.localized_faceted_fields_ids; + extract_facet_string_docids_document_update( + docid_fid_facet_string, + indexer, + localized_field_ids, + ) + } +} + +/// Extracts the facet string and the documents ids where this facet string appear. +/// +/// Returns a grenad reader with the list of extracted facet strings and +/// documents ids from the given chunk of docid facet string positions. +#[tracing::instrument(level = "trace", skip_all, target = "indexing::extract")] +fn extract_facet_string_docids_document_update( + docid_fid_facet_string: grenad::Reader, + indexer: GrenadParameters, + localized_field_ids: &LocalizedFieldIds, +) -> Result<(grenad::Reader>, grenad::Reader>)> { + let max_memory = indexer.max_memory_by_thread(); + + let mut facet_string_docids_sorter = create_sorter( + grenad::SortAlgorithm::Stable, + merge_deladd_cbo_roaring_bitmaps, + indexer.chunk_compression_type, + indexer.chunk_compression_level, + indexer.max_nb_chunks, + max_memory.map(|m| m / 2), + ); + + let mut normalized_facet_string_docids_sorter = create_sorter( + grenad::SortAlgorithm::Stable, + merge_deladd_btreeset_string, + indexer.chunk_compression_type, + indexer.chunk_compression_level, + indexer.max_nb_chunks, + max_memory.map(|m| m / 2), + ); + + let mut buffer = Vec::new(); + let mut cursor = docid_fid_facet_string.into_cursor()?; + while let Some((key, deladd_original_value_bytes)) = cursor.move_on_next()? { + let deladd_reader = KvReaderDelAdd::new(deladd_original_value_bytes); + + let is_same_value = deladd_reader.get(DelAdd::Deletion).is_some() + && deladd_reader.get(DelAdd::Addition).is_some(); + + if is_same_value { + continue; + } + + let (field_id_bytes, bytes) = try_split_array_at(key).unwrap(); + let field_id = FieldId::from_be_bytes(field_id_bytes); + + let (document_id_bytes, normalized_value_bytes) = + try_split_array_at::<_, 4>(bytes).unwrap(); + let document_id = u32::from_be_bytes(document_id_bytes); + + let normalized_value = str::from_utf8(normalized_value_bytes)?; + + // Facet search normalization + { + let locales = localized_field_ids.locales(field_id); + let hyper_normalized_value = normalize_facet_string(normalized_value, locales); + + let set = BTreeSet::from_iter(std::iter::once(normalized_value)); + + // as the facet string is the same, we can put the deletion and addition in the same obkv. + buffer.clear(); + let mut obkv = KvWriterDelAdd::new(&mut buffer); + for (deladd_key, _) in deladd_reader.iter() { + let val = SerdeJson::bytes_encode(&set).map_err(heed::Error::Encoding)?; + obkv.insert(deladd_key, val)?; + } + obkv.finish()?; + + let key: (u16, &str) = (field_id, hyper_normalized_value.as_ref()); + let key_bytes = BEU16StrCodec::bytes_encode(&key).map_err(heed::Error::Encoding)?; + normalized_facet_string_docids_sorter.insert(key_bytes, &buffer)?; + } + + let key = FacetGroupKey { field_id, level: 0, left_bound: normalized_value }; + let key_bytes = FacetGroupKeyCodec::::bytes_encode(&key).unwrap(); + + buffer.clear(); + let mut obkv = KvWriterDelAdd::new(&mut buffer); + for (deladd_key, _) in deladd_reader.iter() { + obkv.insert(deladd_key, document_id.to_ne_bytes())?; + } + obkv.finish()?; + facet_string_docids_sorter.insert(&key_bytes, &buffer)?; + } + + let normalized = sorter_into_reader(normalized_facet_string_docids_sorter, indexer)?; + sorter_into_reader(facet_string_docids_sorter, indexer).map(|s| (s, normalized)) +} + +/// Extracts the facet string and the documents ids where this facet string appear. +/// +/// Returns a grenad reader with the list of extracted facet strings and +/// documents ids from the given chunk of docid facet string positions. +#[tracing::instrument(level = "trace", skip_all, target = "indexing::extract")] +fn extract_facet_string_docids_settings( + docid_fid_facet_string: grenad::Reader, + indexer: GrenadParameters, + settings_diff: &InnerIndexSettingsDiff, ) -> Result<(grenad::Reader>, grenad::Reader>)> { let max_memory = indexer.max_memory_by_thread(); @@ -60,6 +171,15 @@ pub fn extract_facet_string_docids( let (field_id_bytes, bytes) = try_split_array_at(key).unwrap(); let field_id = FieldId::from_be_bytes(field_id_bytes); + let old_locales = settings_diff.old.localized_faceted_fields_ids.locales(field_id); + let new_locales = settings_diff.new.localized_faceted_fields_ids.locales(field_id); + + let are_same_locales = old_locales == new_locales; + + if is_same_value && are_same_locales { + continue; + } + let (document_id_bytes, normalized_value_bytes) = try_split_array_at::<_, 4>(bytes).unwrap(); let document_id = u32::from_be_bytes(document_id_bytes); @@ -68,23 +188,17 @@ pub fn extract_facet_string_docids( // Facet search normalization { - let old_locales = settings_diff.old.localized_faceted_fields_ids.locales(field_id); - let new_locales = settings_diff.new.localized_faceted_fields_ids.locales(field_id); - - if is_same_value && old_locales == new_locales { - // optimization: skip costly normalizations if the values and locales stayed the same - // TODO: splitting the cases between a settings diff and a document update would possibly allow for more optimizations, - // such as skipping the locales check when doing a documents update. - continue; - } - let old_hyper_normalized_value = normalize_facet_string(normalized_value, old_locales); - let new_hyper_normalized_value = normalize_facet_string(normalized_value, new_locales); + let new_hyper_normalized_value = if are_same_locales { + &old_hyper_normalized_value + } else { + &normalize_facet_string(normalized_value, new_locales) + }; let set = BTreeSet::from_iter(std::iter::once(normalized_value)); // if the facet string is the same, we can put the deletion and addition in the same obkv. - if old_hyper_normalized_value == new_hyper_normalized_value { + if old_hyper_normalized_value == new_hyper_normalized_value.as_str() { // nothing to do if we delete and re-add the value. if is_same_value { continue; From 0e68718027dca692e6399d9a8a3350fb74d17bae Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 13:05:47 +0200 Subject: [PATCH 06/26] Add detailed spans --- .../extract/extract_facet_string_docids.rs | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs index fd5949fd9..45a7696ac 100644 --- a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs +++ b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs @@ -269,16 +269,36 @@ fn extract_facet_string_docids_settings( } /// Normalizes the facet string and truncates it to the max length. +#[tracing::instrument(level = "trace", skip_all, target = "indexing::extract")] fn normalize_facet_string(facet_string: &str, locales: Option<&[Language]>) -> String { let options = NormalizerOption { lossy: true, ..Default::default() }; let mut detection = StrDetection::new(facet_string, locales); + + let script = { + let span = tracing::trace_span!(target: "indexing::extract::extract_facet_string_docids", "detect_script"); + let _entered = span.enter(); + + detection.script() + }; + + let language = { + let span = tracing::trace_span!(target: "indexing::extract::extract_facet_string_docids", "detect_language"); + let _entered = span.enter(); + + detection.language() + }; + let token = Token { lemma: std::borrow::Cow::Borrowed(facet_string), - script: detection.script(), - language: detection.language(), + script, + language, ..Default::default() }; + let span = + tracing::trace_span!(target: "indexing::extract::extract_facet_string_docids", "normalize"); + let _entered = span.enter(); + // truncate the facet string to the max length token .normalize(&options) From 9b7764575b43cd5bea9f30079b571c990af36be8 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 30 Jul 2024 15:44:19 +0200 Subject: [PATCH 07/26] openai: don't pass apiKey when it is empty --- milli/src/vector/openai.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/milli/src/vector/openai.rs b/milli/src/vector/openai.rs index ce63e69d7..cef45f90e 100644 --- a/milli/src/vector/openai.rs +++ b/milli/src/vector/openai.rs @@ -183,7 +183,7 @@ impl Embedder { let rest_embedder = RestEmbedder::new( RestEmbedderOptions { - api_key: Some(api_key.clone()), + api_key: (!api_key.is_empty()).then(|| api_key.clone()), distribution: None, dimensions: Some(options.dimensions()), url, From 5aa6cb360056a2b2792b8375bef32b74cdabfaa1 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 30 Jul 2024 15:44:47 +0200 Subject: [PATCH 08/26] Specialize authorized error message depending on config source --- milli/src/vector/error.rs | 24 ++++++++++++++++++++---- milli/src/vector/rest.rs | 5 ++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/milli/src/vector/error.rs b/milli/src/vector/error.rs index 7e1cb8752..3c8cb4b06 100644 --- a/milli/src/vector/error.rs +++ b/milli/src/vector/error.rs @@ -62,8 +62,18 @@ pub enum EmbedErrorKind { RestResponseDeserialization(std::io::Error), #[error("expected a response containing {0} embeddings, got only {1}")] RestResponseEmbeddingCount(usize, usize), - #[error("could not authenticate against embedding server{}", option_info(.0.as_deref(), "server replied with "))] - RestUnauthorized(Option), + #[error("could not authenticate against {embedding} server{server_reply}{hint}", embedding=match *.1 { + ConfigurationSource::User => "embedding", + ConfigurationSource::OpenAi => "OpenAI", + ConfigurationSource::Ollama => "ollama" + }, + server_reply=option_info(.0.as_deref(), "server replied with "), + hint=match *.1 { + ConfigurationSource::User => "\n - Hint: Check the `apiKey` parameter in the embedder configuration", + ConfigurationSource::OpenAi => "\n - Hint: Check the `apiKey` parameter in the embedder configuration, and the `MEILI_OPENAI_API_KEY` and `OPENAI_API_KEY` environment variables", + ConfigurationSource::Ollama => "\n - Hint: Check the `apiKey` parameter in the embedder configuration" + })] + RestUnauthorized(Option, ConfigurationSource), #[error("sent too many requests to embedding server{}", option_info(.0.as_deref(), "server replied with "))] RestTooManyRequests(Option), #[error("sent a bad request to embedding server{}{}", @@ -136,8 +146,14 @@ impl EmbedError { } } - pub(crate) fn rest_unauthorized(error_response: Option) -> EmbedError { - Self { kind: EmbedErrorKind::RestUnauthorized(error_response), fault: FaultSource::User } + pub(crate) fn rest_unauthorized( + error_response: Option, + configuration_source: ConfigurationSource, + ) -> EmbedError { + Self { + kind: EmbedErrorKind::RestUnauthorized(error_response, configuration_source), + fault: FaultSource::User, + } } pub(crate) fn rest_too_many_requests(error_response: Option) -> EmbedError { diff --git a/milli/src/vector/rest.rs b/milli/src/vector/rest.rs index 593d2b509..2538f2fff 100644 --- a/milli/src/vector/rest.rs +++ b/milli/src/vector/rest.rs @@ -275,7 +275,10 @@ fn check_response( Err(ureq::Error::Status(code, response)) => { let error_response: Option = response.into_string().ok(); Err(match code { - 401 => Retry::give_up(EmbedError::rest_unauthorized(error_response)), + 401 => Retry::give_up(EmbedError::rest_unauthorized( + error_response, + configuration_source, + )), 429 => Retry::rate_limited(EmbedError::rest_too_many_requests(error_response)), 400 => Retry::give_up(EmbedError::rest_bad_request( error_response, From 3a42c3134ea84d8688cd1d3a4d8e941f6b2ec53c Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 30 Jul 2024 15:45:24 +0200 Subject: [PATCH 09/26] update tests after changing authorized error message --- meilisearch/tests/vector/rest.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meilisearch/tests/vector/rest.rs b/meilisearch/tests/vector/rest.rs index 71d3c7cda..fe72ad428 100644 --- a/meilisearch/tests/vector/rest.rs +++ b/meilisearch/tests/vector/rest.rs @@ -1816,7 +1816,7 @@ async fn server_custom_header() { } }, "error": { - "message": "Error while generating embeddings: runtime error: could not determine model dimensions:\n - test embedding failed with user error: could not authenticate against embedding server\n - server replied with `{\"error\":\"missing header 'my-nonstandard-auth'\"}`", + "message": "Error while generating embeddings: runtime error: could not determine model dimensions:\n - test embedding failed with user error: could not authenticate against embedding server\n - server replied with `{\"error\":\"missing header 'my-nonstandard-auth'\"}`\n - Hint: Check the `apiKey` parameter in the embedder configuration", "code": "vector_embedding_error", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#vector_embedding_error" @@ -1858,7 +1858,7 @@ async fn server_custom_header() { } }, "error": { - "message": "Error while generating embeddings: runtime error: could not determine model dimensions:\n - test embedding failed with user error: could not authenticate against embedding server\n - server replied with `{\"error\":\"thou shall not pass, Balrog\"}`", + "message": "Error while generating embeddings: runtime error: could not determine model dimensions:\n - test embedding failed with user error: could not authenticate against embedding server\n - server replied with `{\"error\":\"thou shall not pass, Balrog\"}`\n - Hint: Check the `apiKey` parameter in the embedder configuration", "code": "vector_embedding_error", "type": "invalid_request", "link": "https://docs.meilisearch.com/errors#vector_embedding_error" From 1c755c889990a5f8b9dd993a0c811c3d9907df85 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 30 Jul 2024 15:41:51 +0200 Subject: [PATCH 10/26] Add openai responses --- .../tests/vector/openai_responses.json.gz | Bin 0 -> 217253 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 meilisearch/tests/vector/openai_responses.json.gz diff --git a/meilisearch/tests/vector/openai_responses.json.gz b/meilisearch/tests/vector/openai_responses.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..2d27822fefd696f65bbd8c76275976d9886ade4c GIT binary patch literal 217253 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 OoCX#PY1sb~ z$HGY)Qpk66^N!5tGR*xs3zI~^dN8R9SR0S&eP~W3Jdzb!@!Z;6ie(?V-twp0(cLvl zGg2bmVjU_?Koi`hh04iGWNps&A>f>*oah5dlH$YFWN)-6m#aqlRZh83a=VDL!@el5wOVJLm61*UfDBYQWxBIryk$R@l%u!Qqb9whWxa%!lxWY-~ zjED#OyoXmlJk`dL6SCe}80W2cQD?41vhy%t*&cx&x(w;)&1*o$DVYnL~2rE`BjO>7EMGF<6^IId@Pc9AFZx6pvLQSWIZ@+Jk zj>#A$NXr+NTS_63%jHGppl$tLVOZQ1Ip{y!Z?eTr}amNm1P--nG7O z+>dET@Sm&5XC;#|MK<>gPk+H5@8WQ*`3k);o52|s$2585+1+M^T70PF4?252#L-%* zxZ-*FGc^e_zfD;NMJI0dv8exim~-j6iEy_z5TY&O8E$bE|-)X9dqLjQ}^%hX0&_w?NGJm}BBZpC)QRRv=)5zK1 zqXY*T>{|6jwdV;#wT8C)dpp1>n?LOPPgn(tR8>RfJ&_ZwT0N>Pbvv{(=lFGvkWM_U z=??xjjz}B59yu3oo|Xzo@oE!2fy1BqH`_|#t5qHasn4ONKiJi_#uKE~dtK)&Mr%(= zeH}JR$J-DE!;$@}lvN$sZNEDgJCeY^t||$jUb{tiY*P1pYVk51^lgt1uT<3`b)cr8 zZ&FiJq2JyHeLP4%7LUn}o`9 zN7<;=>=4st(sZYZ>h*N!bu?2LKZG8}4EY^}o^hIP%;-O4!1^?qws0bKx7`X&_s%O0h%y7tgcHTHk)V;pL7N9KfE@BAZG!DXU(g7 z=L>U{-RJ>jxSTjb%G|sY=SU?Fhe=u}ULcNDJ_4ds%csNzIb(Lj>=h{Sk&7zA*#KC} z;r{qb6iIeAiICI(aA#-r>d=#fJf(*@vtzb1FD9`ZpuSn;B7$2|CEk3mS`?D&l#V)} znxyU+g6ox}lWN|^ab8fOL$UDsEHdWn6?d5oxb9mfxs)Fwjh`m94WLG$r+Xgk`L+Hd zCoUkHE3Z6l@h!*e_IX?=uXfMB5KN7zceD$vJ@Zzuxp%P}i#lOrT4I`2)C%MX4%~HX zeVtxm!$9U^IaLo|k-x4|aASd`kw$W#Ty(#a3GhT?ix`h3*r=jZ)Kl-CcdfXGl4V5b z<^6P867Il3(my>hfx_*oMayT74x2~M$_90e5pS~84UV?G3o=3Xm9tzQL2#Po7)ROz9n_Z2nI=P`26L{| zol+LLau=5@6R|H@7AaJl+oZ&UBI3p!^2w5EKh{#fUFmA@0mCRNykm8<1x4gTy`VEF>a9LY%$fpx zcrY8q>}5U6jrb_`x8$!WQX+(>p>^OE#-wb~oB5bV!Sk|DVEJIGKIS#jPjNN>JzcOy zF2Oaq{PMglrH%-N#u8ybC<*&O$$S5Z_!o>Uj~x*wIjSaeemdw*qPHhNf2^d4kFm4! zeYYgu;tJ4Nsnuno)i|_=cOFhAsa&l~q-N*-C?x2Vle6H-OIdE(^iC7$xR<;WE=fWA zB@==*Gz&_DRCI4^5W{QRYa9y`7a40Vo8q{=4Su8+N)TVg;C|5YihB_^U~xM~JZVsg z)APW=Gl`OFZd&JV63b+Yv=W?SbOugqyG7dgn_%<8$4wEYAG?T+*HW)Ik)c z8*_1TpWm}O{sN7i6P9lN%(>Vd?7WB7aW%z!*Y2y9ZAB$l-`_~J@XM17gfK6Lf+c#C zbl8bhd+k<5X7N$+dgop>&$IKaBz#Y9=XO0HrvR7SKv|JzHib<1de+C_JU`|?5r;S~ zLS%XVCI$nHnH9)Hn?^x?Vd8iQD4OfYcDEXOPM<2vVzBn=Rx?fsuu{o7Zo9WH#dtyW zE;`>Qv15L)*(`GVlScq>YPpO_IroPU%)rIeTB(tVr9rTpEYHL~|_4<4ShhI#>OYu`HnWl7rO1TnlKWPwpKMvArp_U zm0N+gBj&8zR%ldSa+%PXPZ8mMQQXFLiLF0Dx~-K$>D3I;-}o8Rma%!k1&Hn)D%QXo ztA1sutyH||cF7`mwb~Mp>FQlOnFu?Y7H8b&a_)h!QJ2QSpo1V!(LqA23-e9We<%_x z_#nsdTL9#gZ;JzJQIizJavjLL{8`%Uxs%2-yqzbZ!^|uZTuM1d?!=5@kpEE|Ze9lD z&!|H~l-%8Us`WK2s9Vj({2i?2^3%SA=Fu=;Mq1#^IBh!_$$DINX$)&WVX~T2?VXE6 z(ZYo6w{OZ^K41f)I`>&ys_2><5dBVv{ep@3q}RAxg2c*6q zt6TMFuW{Rs6Vb`;cQR8u%4xkD+xrdW{JD$Bi<05C`d5F)#Zsl`G~w&D)g1h8-ucyY zR$zIj#k#b&Wl_PYumjfb=7{1(lic;s-?v51I}_GZa9JfJYV2+QdbY`|aYv8BNjD2U z$BRG#B6}K!uy=SY2;nKWKwDDb6+IaM*3mu_X|sqpV6oggg>?}D7)UVH51n{FZ{+;W znlYW1JIOtJEt+0Wxl;rN+FxN0BPtmS6EnDY)!YgFy7k8Z3>%pbFEYHhuJDfgVxi>a zeHh7f0bT+FYX7s=Odd9JRt4Q&k=fZvU{yzU+oA2VZQ&*V6=1akLwJIB-iF1&rWHSr z0gS<@v}-(mrR0tnes4vBV_oHZcf{SORF<^Lw73p~e^;~A-eNfSoeNy-64b>&eSAuX z95nWF6WjYmQ%p8BR z>3rHRjVD~`s+pS)=90d=B$A=$J_cH-ber^m9!l5U&SQXhUhgsq#@395o_jZxoG!^& ziPU2GR=$d~-VKH?8#Je2kJ{3E!YHXNl|ThWabXD^3ia-YMs%>|NDBHFwnlUiu+3PR ztGSyka?2!k);w2w%r=68f17MIIqOor!cV)4l9ZxScVn~8aQeq$d@0@XMG_Dx2)ghHcj(_d=7b%A2B7{Me!tDe3|sC?3yTawqbHlf3-G zmm8|b;po=ycZ(_<0gtgy#1W24{(3G4^_aK_ugVjE%fxJd-sLqJ6mPS3kas!M09j}q zNqGC?9Y*e6ySzmt&&NKAjF{V6f&U7HXV{_@bGHKlx`m!fXVMWwb8cyQ5iOiPH(dLh zOtBm6l-U0uf)yhKKcZvs_AC%wy39Kiz`1SyFb0q-5oV2Vd73h>^-QUlx^f(=Rk;`s zIIR`4mbHy4ipwsikO~rpZe40n72RERN%P3XcOSbKyVB#ogv5vt?^-MN=nAHq$rW_R z^i$v<`8rBP4@PP2DEJW4Q`EC0F+a?oYC-Pc1XMMvrnqb`n5=)RL2- z?>M8HLVIF&QzDej;J}Bo&YKdY5)!tu-p1MYP8{nskTpBgW~i~$5Ic09=^70NfHwWc zN#Gs%JUz(O8PVf#Sy@ZetGocZ1j8^g5S?}EQsKl~X1`4IuRr|G-{IV7hwGmA3}gN_ zNw=q3FjcFkLJnd7kem$olNmfIobAyd7K}A-OvhK=RyzlRl3GR5pvNsDym;-$Z$I$I zxuOD1OZ%m%P9xY`ZNF4@Ay#>5I(nDtI5h-yN@Jegqet;eAowhalBAxUvvA;8rxNhSC_MvLI zm7Gr$pwzpE*X%*88_391L%MTiyA@K7u5 z+pZ0|sTsg*1wCsa`iWxje)av;I3qB1u=esx0A9>*j3M(#uv+k z?+cvm%|CXtP+;6$^Q6jtr~vxn?0CE~uig_Q`#}=otpVpz+8z$J2@%`#0Wxz+g*bfpDaM=l#+K-rOKF7Ht`f|K7at z_+qTw-SIE>kdko|p{#%VpZ{&kWF5E~SDJ0*VDPI)(r>lA(bsw2+yU13X;Q@5YdtQh z+u?2ZN4C$7yL3dZyEI*o-2X0p_!Ee8dCViHpT*8USxVq1zurCI%wf0lO%qt8yHPU6 zrOxFU3bgW;r^n*46uF;8EuOv29XD6u%5FYeEQ-svhu6m^)m17|aUeWr&)kb3TXOBo))01*5~2Hy;+8yWx!7n^`$5@=>*v~1 z&&cEz2z{=#SFS?z9%GaOJy~&~Kw@M(=MFCOWRu1vkTYitow1>?ZxOAC2+y!)Tz~Gp zw`AWkYP4r%hHOu_Gb|xcl>2Tk$7~zQD6OspMhp{0y|tSRwnmD5fW)(8>rciEx@RQgF8UHe`sB8tzrUTIV-pWR z4Lx2NT`|2Uc&<%NY1Y0RHCdZlqJkVy)+ifXBUisDbqjMenTpYSUrB<8E|VgyW#z2= z_#&nCn`SGYRl0jED*N$(DaJm^=qEG^l`>&WO$YH>)x3=_n>E2TnLF4iNluW9+B(ql ztsWqqa`Q!UrdP#Mc*=H}Mmmtw@eZQaw4VX4keeF0+c@$ZSpNR+4L5d@R5GLc>gnO|D|FIBfjNVb%&gO+72v zt556V8s30PrHvH7-iEj0oO{2hoFQ}?0gY$s8Ek81(T&ZGDdy#k#E4Iu9YGp<>0iu0V^$cu@|Ov)m#Y3i)E2=V@qY? z40Wk+OGPFP2tRCrk@4U_m#q@&S*y$oq_8&oj#6_ApLuJ*Ii3YER=+$`QA~A5_?W}! z(nfQt>3=4}S7URN-7&R+nB+s`uWTJxg^m(uaTCtfH6x1Z;xxTO5558>;iN-@DqF^2A%h5tS+?|#DBZltyl9` zQLC-DnRcO(AgreYwJ0R99R6_kC|6nfIWb|}Fvatj4`=$O4_ZDmWjD9zdOv_Ssgpq`SAC)e|C z_qvk&RNm!L81h2S&y6OcmfOGpb$qSU^@o?JzwPSVCF^rtZpom@f7d_&OJYh|Iy)zq zJMYPw+^I9f3>Q>>8~F>kd_yn?8_+#3(f4Td{@8Q$%X#dRD>wGTNWnLQ6C7EMLP8bk zqomeo8@*iugcuCepp;=!#NdSwMQz9(vL5!{J*Uw#CS#7$F?@r26wu@LuSAx_jE6FY z8SdT~>cuJnK^-T=wc5?O6B)0in7MCWF`|4)ovNSsyuI{csdre&y{MU#U{?{hS%B$1 z&g{iGJZ{vx2@uX`^Hs6#v2ZXs!Tr_|*%tFEf~M$!^hB$7f$~y&_n>1zmeC_C?3T%a z>}bY2Ew1sdp^wYDi@m?|e3>dVb@lX*+UZ&Lw~rPWi(W|B@hA;)NJUe-F*-%9Kh=3` z{ze#3sVXoSbkrJ3Ty;%~PKMN)^?=XgopcIU-#s-8BvTxp6YSc3ym&}@5=Ww^QsD*P zAB8DL>2j(4{p0j$ax-D4hr&AE3Vv%HrxC%C(OOjBh)2g!>(=4%Te2m*Pc18HS!28S zF9-8cB`@9xc{ZxHNDyp3&62wuk{Kv^YWv5<8)cKFuugS$U{?8MTj<1f= zJ|hePn^*cRw+af_Um_qw1`xHZt&u{vDIEoMLG(l=@h8>`C&?cB~O`RDiL4 zjJ)b^j}d`WnuR;_XX%0&#Oo1cl%Tj}H+wF~Y=wn9nJMc5;|rBZN8DuEmF-X~PjHPY;RZuE(?Z7UJRgB>D7-Cihf8_(ZVlJkx0cg4Wt#D%#Li`f;&XVE zyG^mp22hswAhKV*xu44QLnSGHB%;%+ z{+YRacRzHtt$5pU${Wer5)A3?n2dLHGCmmf1N)$v18Msi+^NN@d8GL5d%fb_5uuFy zUb#kMUobtI(!_};Xtip7T?_?USI0Ze0#x!h7y^Ly@Zvlgx87%-h-s124mKd|RO2_d zz8UTK zIUK;Ml9le+A`=^q255$@{Z;^Mht(+%WbqJcGOwH-=Z;4)dA`P*tq{48wFx>h4}=f2 zbuWA5MbjLJ-dH=Wu_m$_Mr>a=&HRdEDTMOL=_+?}Qh&aLidc+S5?QFl35fyaFfkGV z-m{jC$1%C5v^m&a=d*#7^suT^uI6Y*tuP??SYMVw8o_4~d8W3xG+c)Z(iAr_C7WD) zIP`r(Z#*NdpCwP6ChQ~BW4$F%lveVAkjR`Zz^b>t7qwfQM@v?$oRJbYV|X5xnGI47 z{S4OaJ3oQe%vxbJQv9oB-RG5k!|f2C;-oI3f;Ipq%m1|U$#Zzx1!Pe#nmGSxnvCsd zy`aAf(ZybgQk<^kop{8(y28^)!PYE`uULPvWVF5N5JYy@pLFu41P9PjcT}vj7wf#Qw)KSd>2J!vk zo-n>5QIbl<{y4n!S{}1=NU@h$Jj_E{l%(%foHo=vmTw$JSU~-nHxC87V_?h)e})|) ziNrtCdT)9!J`TAIsb;Igcpe4ymX&Q2Jf_yszW4Cs<-FlhPoX({th)@X?^s8%uHx8v z@`>s4HN730l{7VoG+0r3nzuC2oGU9 zDJ>&-oOHP~G)MB>>|6W0OIayXUQI4KbBhUWj#=I*@fAzRu+UYK4r<@#WzB1ykCkMv z%dk&dx#rJkLQ2o~GS|1Y5$8L*nY!XTxj_4c=UT)X47nMpE2+>Hsp9HV1;yoOHKZ8z|C_SuheYFLc+0)vsBHl?wCdpR82{=8)oxuMaE zS#qb&wgMU>?uNb<>GDA#0#a(A&#JYk-$>Q2hofi=zNRJ^QG9$7j1uK9v#!SagXds9 zux4m+x$^Tzj*hFo>QHHXK*DyL8d;H29hNzvTBfq~=o%HUK>|{h)3x;E(^e%Er~!B$ zHq&ew43sE0CU|mE$>)UA;8tj1D&~GOPUe%GivuxSl@@!mA6li;f{=UO^QxG?=rydm z>L+Ts+R;S4Q)&vd8@(y^(@|jGGa2Pha&GcTqwWMTTg>E>MMC>xVe#rt?HNVn1;X^c zg0`7lXmL8CYz&}(JJ+cC z-mcrIkw!Ja8NO3nAAt!$u898ouwSH9mLM4a0> zg)lXkWzz?wEi+puALd;Ra2PCTodX1B0kPlkta6m~Y_^@r0CzWdM=M7O%a0p-@J_0a zuG}!MLAlwlT2pb?7~YX^w*;|L=yeGPr=xN>tajQUTHp9{ZmBMo0eX7-GxweDe?sU` zswGdyEIey`yzLJ7y5^<~(kShJ*pt#~kb#Vd{Ei&l?RG{d$JbO%Ij{Vo$hjX4OCdH> zLz3`A)m>wPkuI}wQt}IxX7o&&wPnMGx@VB6c8G^>2YP5pBkul|W+9}J$Ss|N##vmq z>O3Cr>oA$O@VqMUW3N>kjGGR7Hzel;>i~6}cJl0@_8mVv3Ebbf+q+KZKFLR_@@YsY zGC0-&*t%LfJV(>%n^Z&NVHR9O9QZ~xZu#Wu^2F@k!5A!oIm_}%Ij_4 z7?E{WGcE$P+f-Y!W?yDJy5-fBXlsLI8M!-;mp^tv-*o)u=sgDd=~@jzF*67C3p-kj zf)#nT(}BKvyGjQ|eT7k&W**uwA`svad9Rj=#=M*xU*E2Iuq z4JZ?ZFXv@W2md2_3?o+0>N$wsIlH|3H2!Y{m@D2&=yfskqvYmU?pl3F5>%?)i$RM#bnFa*_U69C&d|6I9ZG$*e5fTk z#y^(hgiaC}U$TG|RMew}a#$ZL2X@hR^(IpmUWvY4$V-}7qB^oyzzl~sXZ2}G51YJ& z!jf={JDoyOHse8xE~`wUoB2Z7BB{nyV`;T%0vF?YhpTSXU@d%UgW!52(mw7nr6$y< zjlbmnZjk0m0oNgr-91Q$H1l;AP6JkUe1wAftYtM+r*{7leP$`}r67gEj|i)IGRTDc zOPC}JuqBOzZ1j%iCoz4p*T4UP=Dp`P+Q{X23VzRJ?t0_=bVVZ8f5(&Y9u3-*(;Wsl z`lbRfUf>jy%+o|tprqRqX+JFIYIewzKaYr2gtBHH`wwK)b050%-}QKv=3vKcjmTrg z%XsmpDLh#*VKJM+tG4m6hsj7ijKoL(!n>D?N>u4M%30Gsbziiym?KxRBKKHYCTIrf z9G>0CH-j`4t%~@(ogY!LHYnkn%wvvQhcs^;GjPkt(-pLXUs)Ig1P{9$RCNEuA40SAQEJT1!i5!;h*49ypwz&b5UPNy%_?HD4Xu)iroC~N4DzJWtC!Mp?V2cRpE9*)>h7fzBPAtuEkHU# zx&%#bpOn%K`>jU?zbue=j-(TN^{!Jo&`VaM%O%1T_FA}~==@7mKF3`5C=Li>4x>=s zaInpvc%!X34Xj^0@F6P_bVwHwGmhF>%Le|?Zbd7Q@)vkwak&ExAjy!OuCyo~V!JTkYR>&-@L zIWCAjI3lL<1GK1S1hpv2*03SU9oe70(H>LweLO*{GQqu^&HfkjC~nU`Y2AM^gjnLp z8;Aoux$XzumL?r@n`qfvMY@NPB`!m`psd_%H>bw zOY>vdmzGp!k-j!PXi|5HT;eI^8b2|bE5i{@X1ydDd^M3;?@;U0T6K#*VtV+INnK-0 zQ)f|3NX!;Byh6$H!pKj)2>7?xZ<_w7P)IWmDJHuj4Ctr7A%k#wYi@~eB(#vPWcjRc z)1N25#_+?+Jc=zr(aezFky4mhw4vy(bP1I=^M$|h_n z4N_8_c^lJ#I#iz#4bYKYl^X0N6T_UYtVjt6%yY7ifunX|psmd+2fgOmEwnyYfwT<8 z5}NtkZEFHe8cftIq0=otd51P{-UPD%Fe%>9Q?nTILi)m`kp9c%*fA^F0Gd9x$% zMgLRRUIF7K-?jw-R4LvXgdacP%X918Mf{Ojs$8um^^{Fttk85Xa>ojd_n9hldj?%O zxr!nd!jJ9{7j~F(*d2Z`_Y!m0^sDb9|C~vb?43SIP*R<>DBoEvlBM@y2&l+kzwa?} zJ>FS?+^G~3;3Q2q&;ikNXS`k9<%IX-wpdWTMHAGRJnn;3PAX5rZys+>s6YY&CzaU+ zE{V^C&*R1319PbFdaz${yAq2IGh@het~?p8@O}R*_OO%={WLqW6uswg=$2<&w8E5^lNfrWwOBa z2diZUA#}3iiExBVt&(cX(A*!~Ej0vx$#u@qhM7C!`2(!#a{fNT8;lj2RD*sx1w{#} zN?Om%48{Ac^@RE3u*+;izRx1b$B|%sx;ROifP%;}(1&3XlUMFecikw^aFwsy z65l5n`TSsNr6&@Vfa6+5a4Ra(%g%lv z%$Ib~dFj=xHy~(vBtCUL)J9*@{!u}?dkxhS=0(^Xc3B3Tn7Mn$Gv%hT@k0jArN zum=9adTy8dB7GCN8|t zpbKXh+s)nq{#+q2C?;wh zwmTcW483d)Q4l1TksBo|q;5TA^kTc$xS^6Yq@^|Q1Nv{H4SLl%A|pNQ_6xsJG1sXA zNdEFc~WeLLmb_0M{S`zL>i**}C!N?>9f zfW$UfzsHc%|1o!C>dX@Mjw2a0-9C0F(qKo9MwLDOHR@|=6|ELCQp$EK$WkklE+fj(1l?gj_qPU~WX>WmdDadf6J z#4{}WHludBOvA)Zl?WV0>yJ>P)%}>105}BF^m^}*;XTP!p}HOw4WGo*F1kVd(gx}i zFJrATVDw5l=XS-kS$KkNy45fxD&{ug8l`j`ZI6;F!cVpBQW&@(ZtpBtrB~eeCVxU$ zIjuAfP$i8i2V6nT%|hYYo}(XdWeh&8*GzLjLM+G*%k-~AwXV|A-Hx>m2_sck0<(hs z{cr#4x4-@$|M<&)`@jD0KmYNUfBZlH@gM)+|NhH={m1|K^Y6d?*BrI_@go?b1OCuBnHGNN8HmbuNoTb{`E*s^jQP{{c+{iSTChg0whEuEH>n^1GfqAaNc9{#1>J_&56uI!@d^w-1|bxwbx z?{Qn!?mFIx$#_9fW14zygHpj;#}T%obWk~XPouvvd@1QMfETl6Ebke-6T1(c*rsD7 zQK`_?*;hJ8mdgD$BGAYRiBmuoy+QKhGjJRh&HNid|mzJWtLDJ?uig#3AhgwP;0Nz zLdM#h1p?MI7MO}Mg$0iz^934vk9Cir=T(L47E-28o<`k_6F7C(fpkGY7aj=S&Y1=W zbLS*$le(libDU4K-6B0uOI!Rl>?7>waf8V?uFrdpUkX;d84qn)-DkCSq?yEhg{ZTR zHuSwy>XmdsdEXrhoO&f2HspT7{c#;aK~|PUW=JO+J#bULulJ1Uc$#^#c*L&mp<$}V z#e6m`iEzQ_PeZdArA8ur$wu`KV6NDLxt8eet!GF-CN&+gbX0>2oWtYk7?O4Bz@d?p z2nrx*DSw17W{T|~yQ@hsItya|-~)ZUlC*#wMJND1nueDhFsBv20uX1(_62^>hQhF5 zn6FMHm*wKMgkV<~=knc48c@nCwmB;UOW*SA420HU!EjxfO?Yyy{E&e5;));e6?#z* zDS{EIq3~qavQQJ&K40lRsPIIu}N{+7UoYlz36hEXFD> z$Ua}nNKkmUp!qx-F3~0fSZ|pw>e*psq4S3SDKARszS)FBVeb~yLyK)~Q6RVOO8`AU z!oM<9OGjCX6^lmCGyQOzjA1;100|wz83g}xq@T_=sH?( z=|S*eh2@T_qvr#CTnx3ehzSdlhvmIWl>|!IZT=eh&tWxJ8rx?Y{lRUiMkL^PemPK9 zdgdC=GItj~vj)_+NlB#h&fhX4aj#*zWpE!U#=Ml(27n})s`Pbu`iLVPk#i-22pzgj zgYMN!YoU|ooPfn4^1^&T*J(YsF<+dw0}Ldta=qw+RG$YcO#iHZ2oGK*0O&>^reQte zm)Xnh${Fmy(~<&Mvw*=_E4d{g)uO(Ul2c;!LPNJ|*-;H75dbNQJEgrdz zfK{(Q!SCC1iwA>Xiv^!CGdpv0ZwD`vo|4rqh!_KFArUF`e(D?op)-s56sZ@pP5stk zEdYEwK}l)S=kTD6lm1wl!@_d0w&0+m6Xqr;87`kFJxb} zU5iwt z(nhMIIMrWKx(8HHn-?HXaf*)!hiNi2rV_}xNbK1mN03H?8b%AeRH-xq3=)-@$RvZGt)RwnNyryLIi|wI0m8 zrt`4UZ%)i->RZw$o*L@XoP>m@Br|bPvFNZz4AQ~^h#gxUV=gH~VbvYK+MU=gq>R@4 zx#(*>sdQaa)ZEWCt|{EXwCv6qy?RN(*iMJhk+dQ5ZTJxRL0gZS-dVG<1~bx<^~-!9 z&6G!k6P_zatLn+DPznk|aT)RO@}yM>ZpYRl+C9S&CX)Qn=Pe=~{Hiixyr?et{C$|D zO8)g0J@Hs?cL;D*OPey)WU&Ef052XlT@aLX+Cd>VkNKg>F-|1J zO1&D8mXht|Ct+*Qf~75u2Ao7moJPbk(64$$N#RC*-dMS0MTehbr54^oLy z=VK@q_ulLf!+hKAXEcn{@Cx!rm$D_Vuw|+P)ZOT_-VNVnV%Mtc7FtKe5iTHJ-Qwa4 zo~nFmjBfP@+&0dh0%32e0c)qJM-5r@@>z63#kK2kMI_rSXw*%zH;dw`#^F6ymTu&v ziEfe>B6#lW#m}l}UZ{0RFe)TtTh&>D(8KV8-I~dt^Y)tsyZre5=ZC?zHdy>ze)Pus z42ID0!NCYtdNEV+XBgc)tLM~TJ9{K|UXRcUps-{%!IcO3wb zTQUVhL(O*9YhEvgOf`Az17n!j#EiGFJ}rZzjU7w7 z$81YoNxX;dq{bJU3YFk8DyN7Z)kYhe~iq>>Z+iO zj&9*@Tq_fBiB?jYO2T?ge9iR|c0SeagBXpN)qTFEnkGviV-q^l!j{{FFh2UZ+y!r^ zwBAlUG!#~8{TyeqA(#S6B!RyiUimi(wPM>$qe#jUY8103tAG#~Q^sQ4>EW@bYpAT? z)vnN_!#2Gz=WxNsh(K%YkX~e-p(f+pVDeu`*1?Yg@R`GJ$9oGTN%`am0 zA7dqe7dGKwSOodtRF+3n@D1L<;rtyNTAa2ihANmTb{IM0eyX^hxVtPBh<=3@3Vw6JD{up5D4MM^m$gzP^&= z!lu$I0S|WB7l?_*^(2HXWJcFI-X<`g=ZX&0Wo2ZN7w4J*<#WGk&!56a&?yDX(8ns_ zq0Ifft)jbI3~ok;d43D%0?)f0SyQwl>FYE(Q!z4paxPU_1t_VB9w_^sPqN_7FfcSI zgaJ{1Ur~s1dx*70!*P-f&Q9kq9pdxLtv^z~3Y?52JZM|>S6*ISwDmRf-;bR8pO~6! zxy}5Pmf*^!9NX6(M@hy#F}x5gbab&vv_$|xE5C!Sv0T-n;vBXVLrn%MfU zAaW-5r~!D8dUA<|LV>G&jCGmY=BX)mUP7&Rg<|X)RXokG+lQa9I(=HjQX<85{j~ff zx|rq84A0%Nbz7)+J1s=8P-q$qnNo7^2DoMhD6pu!KqTB!F9}m0gX=mlA0wIQeEWQ3 zKB80bMmI(NVNTrE5<*%Mw>PsU0RCz60_$#7&A9AH#kui6ERI@2#MFlwXe-NR+@#HJ z2F)z6J=>~fDk_1Pihr7++a)CX&Sb(jBhO~N+g&r04?Op9I@Ib&=__2WeNY9;$-T6Y zR=bN)B2=S^W}M02k;UjptyfGW0sQK zeVarVay`XU(T)LQx~}6PY9w9nW~7IGNLrtB02PU;MofFm^N2LgoI-HocCcoW;WV@% z=5(3OL`9Uth9i7D@9bF)2q{Br_Brhp6z+RD+CY?*3w zAlSD%-vQobwPc?Y1gY@Gji8i(TQV5?iH#DL=z53G@We^kf@^)MA1Og1$8Y>SwvLA& z6b!qb+v)Otv}3~tfxr05(_uX?4h?V9ba)dke|zKt417UvW$g-+*@!h4-YzJWyK zq;+J~jKzhq(BG|d2kCxgDwXM$=etUUl?&CJb(Z)WpD%&XloVNy{)f(;xr%cfdct{; zNCa-pYF~kz=r13i94&z$kie6De06L78OO82TSzk)-Z_rMsxM)n$C{J(C~0|t0LMs= z@wxXOgDy&-y$`8bA4|?4A4%54{8+Of?pXJ@m}6vn%1bzfmJ;ga=45LfRBw%jueLvs*ZUk;S8djhUTz0wni zQu;~!MK#Z4m1q%GW*u;Ov|b~d^J6)tA>kjklRUcPG{Y}IMq;43hFHvM>Gk%MT73B^uoQc zpBEWgyJuQ=BaeF+4AM}X9l5S?OI<(ckceym-Q-kLLSW>CCp@wPg zRoWoK{&)-gxRx+2k0LUrl!>K77o3~MpiwIIAIvr4ZE`}UZYM2bu?jnfLKKrZy z171pWM+;b6t_QOE*v3BbJ7grrBy}j8$>oeLvhHV|1+J}VY}O;W{9BU*>BEsCJZnO& zBmkbQB?wSucohf_MDE0A2M%~h!SF!=G$|hOpDt2QBrVrieJ=69IXLs8E0-2$Pmspe zr=72eHa(u9R?HEIqar_H*k3u%9)RT@OGYq6Te)jq{`!)wUvjeUE}J-FSyXI?zCZ}a zwo1#T;q~pIPGF=la9%$;W34M1#8Gnnx}9isRk>?@ zORy5=dRpzqJ1pu=GgHZF{YmWIT+SJEej;{xXkGrFqN8 z?el8h!VqWRM^gg5K8+ICI6X(T=wf+(xowsm-1+2w)#phxj1ubgI0ht> zOQi#oK`mbNe1qA(Ql~YwU;Cm%lykh?>Hx}vvw6eKM30kCS9S)nVLf#;c14ldM)=1X z{iQ*c(Bns>$FKRH>xp$=cl@4XRW$0A)F4rk1up`|L-4#=s`O&mEqR-*hLKJgLKWAT z8YWOo6VUizqMKPKPrxl4QKLdyKfuqay;QlKHN|EPoMShb!r&2v}p2%J}y(`^Zj z=`ruH3pilHjD*;^eA^k74f`)7#8y%Djse$t0&0iru$TciEhgTf2M!gN9B0nx6sM!v z%x>hVYY1jM%X#cd)MRfqAU|Z?F3b|MW4!QXscku!PIa#+nKrca#~oI zh&Qz@E8#n)#~VPCVwNS-to5VJ1Y zuvUng;q*z)^Gzd7Vnv?;%nY^1c(nq0D354cX`s56f0&diivp67nymO)ri~zZ#APtX z2@CP@)0mq!>)9+ON=%tF=3(M_8yy2=W?Z>1Mk<`n#{_OA$@HLK4b2J)=E#A6P7`Vf*qm2`=4Yby_XFhdHpHpM|c!hw} zUHlDHPL#Q#n(hx=L^Sl^-H0pngRv6#KM+| zBvv&Nt?0G-76#E>H_d<7ZbMzmW?A!&M4?JbieA__b7(^tzfFZ*S;@MQS!A5*ee76r zy6#Up*p`}po1@i>#B=QjU?!OD{c17#Ug7*{i@`yvW} z>&-19L%jC(814nI@kj;Ga4Zt7g0^6C zmcbsabu~osSvhjDfTr@{$Uwv46;36~I&2t%c!vaX)T~t<5YmIr(cZCT3Gr;pDnpZh590r>XnN`4wP$3S0J$uaJbE(KQWs86Vii5G543J)1iUYsnAYP;M)eF?#lGmQ zZ(D@UFkpfXNGM5TWAi|VIha-9E7LAJSD~nJWCb%{u!ckMmu^YKA&z=?4;t_5 zd^whgCuaQ#E;$~;g}SZ{j=qIFnS|z)9Zgja^%JceI}vWS#T4e|>UOfU;#mB6lp7rHX04+7l;3&*bi$j4q6*)7y-v`+~UVN}3DyF$0muJnM=VB@Q-es1=srtI6TSxx~wZ!DgBj_cn~+pwa_QLOt*Q~xsCe1@XiwiJcQ z=4F%fc8r9_ejaDce+7Y=2N==?x+I8@-l%BP))&08sam19J(3uEr|=AAA*0e*3pY&y zDbuQzsVjL1Zm)pGDSra|MXDq+f%UYv!}N@0!KLsMLc2}`bPDm*fiS+QG{zKes|XgbZ{_s?@1gP`&nJ&I)+eH;N?;yBsgCw=+sm2M z%+PvvhIwh1u?HpO^4v@ROf6sp-IBs1KKitp-+$XUny!C0ST0ydmcKYg;-`gIqgn?D=-Q_P#miwKB+&Z~x9^C8epSs<*5H8nP)=3* zh4p%yb@9~bn#S+I^Ay$_?iN+95}1t+ODAh3g?s0e%JuG~CK>=hkSs8~1*r5TbVoC$HN4 z8gZK3cUxq5rv>ZqU|4tjq*v#7V(kD-KqS?G=v{F=@RmjM1y<{ApI>(c24+?MeDH1KDvz3rp}lj5?MR_FZo zrUsEDRg@j5b&ZlTf-_F3{WWv0bP?SDa&FQPQT!a%dQQpqW_qOSA0b_}PK0@s+(Q1o z+7dg@a6c#LQxrMBY_tp*)TdwyNG3d~JWXHhwktBkb^E8G&IO!U!2wv6Wnx2jw_e6V zU5po%30~CO7P1Em^Xi{GM-l;OF6Hq*gEXOAi+mm^rN5ZWQL-%%uGR`|FDR&nWu3Oc z%nnjtW|jzt7vsg*cm7iBGmirmqvD zfE5M@MYBgu8zTZ2&YZbz>FC?UiO)iZ|2XUbe&!HhKDt&^17q0g9q~b{vyz>w;~r#n z;`uZmx;9!X*HwcFx{{z1NVroBO}>vGWdk7<{eEqY)G9$W@f7wrhiq|E1NACpHy0ug zsceW{y`J?3XvJbtfgEFN2C zf6U5+U4sRd8t5}ywpMXM*_A=9-s`&dafnGkEBUdA=v;nXSw^8yPzoJ{zTuAii-Z59 z&xKx^JKQjS1W7@E?)K&e7W?Q6)Yw?-3$sM$|74Vkhr9X-q4anK;XWWP8bNfA)J`@~ zc0H@N6Ye3qwMBEB@?mF$tD*?!Tj9oV6BBr?b-v#XU_;VkJL9*M)y4%rApHS>9wZ|C zD&ch#kDUT4yJ!oPyl#tjWg4!|^BMtWL#PThqD0I|iP8?*{IvKq=m&a$fFz$)ur;6{ zw+I|8vO~;>fTWJJ1Kdiv{blb^TJ!|E?tAz{EE zv2+H`d&U~@BMVU?`}_*h;5t+igzijV^-c`(Yp9;eiq7X zEs@n72Xad;fVWMb^tn;yr(4Kwp00=Szs~U1IUi^MJ&JZ^*xZ_V%ml)$GZr@Wu6mSP zTaqn~fL~Ie7{LsWNg0-FCt><(7iHqoYvBS`HvK`-BDP5AjqJSR-CR^@O;BT!p}={E zLY38yp9WUa3yJg9$;Axkrhh@0HJ=23y4PTkX2p^1sJo`SDEj}G2?|FX2dO^+6=>Y4 zsCl8=lrny^KJ+XEw@ouHL5_x6S0*@=I|doS^wh!i>9x_O8m2h`=1%A+uh6aKipX2G z*)Ooe!sxwSv@hEhP0L}kfQ}d4i^U1i0MW|@HC?ea)FsyiLp*v?S)&k<-QF`l_FJ=s ziaA-QHx0b?bQ{g;W)_F#@LI;TJl(TQ?9lP|fD+U`gPkc&-WeHBTWNuDu!U>H){I^Z zg!5oIkH@~*NJPtZXrnkL&uV@3T!zEr!@1k%j*;MDp(<`70z8x{PN+0_joS!bU!Ks< ztoXa5KYe&Lt?^kstn|YCySe9rOXsPY6py9T`v3Tn+7)VfWi}(Ym9~1Ywndzov~qZR z$5I~=p3>mmlf|2A+}FFIMpkeTA1Kno_n1Z>pxHH<5P177^tswFaO%qHOo0$Qf6`u;m42PRf4H<+N_$i8W2efo*;Eh=GlR2^qs{x{*UdD%kPTxh|k$>y_PHn<+O>J*_6LVVsBI zcu}e&TjQohPW2dR9r_@#hX;U5+igXYR!qXg_P1z`fGTFg)5^*65mwW8brxoO}U=T)`(R->aj-l3Zh z<9W6HNlniSXojXo^M&-=S|l;Z(D|}+g4||V#~_&F}Q>S=LXX1!Ju0U_*EXV+HSv7cDmJ;pPk3)k&=2@@G7@^6ek zehvc}aliPYhHGeo#9p2l$prb0D^A>7%Diy**x0ZO?||r49VyJ!YH*rxMhSLjX@_MsZ2a z1qbbRNm)4tn=MdrQnB6#+}2U^_%uvsy@Cz?n+=oorcQLL#q>n6JdFkByBf(#Fx_Ll zcZMS^O{}i8jqSm0wjzOQleh;u1;_Jt&8+%kh?$SsnL#`X6_xI%iK6g{e7ww4`cR46 znfZD0gjdxg5*7joT{@q^WG)F;n|F&~u9xr)L&;h@z(Fmqqu#>7KzSbij|F{M%+`P3 z8t30;GFFlE(3glK1e?2hhD z5(9nO24f6un99Q&}S*ICXjfhgcwe!)|$c4 z$r9x7OO41G@P^0*KUlWRMJ|)vqD@`glld^9XT=T5Lk}E#C>Osw&dWLqab1y9Ilpt$ zgE0b&#l)}f6FJlDPN z31dJ>W`z{ul#N=ir}>|BfRwY%CudR2O*km-@DNogOP9D?>T#!;+_+pi2ye|y;!kTE zT?IAGQpGWL4*X)lXU9!@-YvTpPsL^OLcqpvfsHpyh`~s1&zd-{&wTMCl1rCzocRhn zN^XgRIocAQa6qj`GqzCm@cM`)lw$pU&_BksAefrt03TP%J`>i-)Ci2Gn)44vmMTav zAxrtxxe`>|F@c{MzPoUHKX%rF9Lfe=-nE$Y$BI5Rv|@@_E}!?zZR(kQhEpw@Pj&OT zNx1Y!iWOiW-xErGvx&X`2O_@)UxCe6Si-@Fz>j>L{QJOrXL%we$C>04>b&W=X=80rEGYh`b)G7m-@|i1 z{3Dt%OZXfeNoi{_*!!{A;uFB_we;|{4aB=iO@XM2qKqm*`*D5 ziV#0AMUTXbU+LZf^e8KsS!>_s;6v>MO1YjWUQOBWy2AI^<4Z2mUG-gRxx|27Y>Pc? zfQ2=rR0Gl#`R7JXw#`SH7$EoaSj`0OJNwUI_1$i3QE|XH{eU-^bg!*R{n>)`3F@V! z^mfTjyv48d)uHv#c7^xejb{7k5W6^Bzr`$UEws*S?Z%mnMYuGHpwgUxoF6g=#0d-35aytnMjG^I0CwjR^w zKWgBEvL_|kXZHG3b6HX6(gL<`iavPt0^?5JRsor7sTQANUj0s?Xk{t5U=5V&a|PG4 z`=>F{H+x_E`QomBr9~XGenCbuuPlYTqZ2*r9%Dx~=15RR>yxPBb% zn6r9Hw~o9L;-P(b4hH z$9mK2^=))uTDbQ9+qE0YQf7-sJ%hv}h>g2e@kDSz(70vm_uYf! z3h$L-KN@{W9j{&(eqKXg`63S2RW7ffl|ygH|BrQ8v_mj!c1qEhqz|wC7t4@o_)1`B z$T@Y00nATs_13foHFGs<9^nDor8>mcKOKQT#v~h@DlhRgY|-DJkDtMy?=4Dn>I24><829Z_o1}o5s}cT8JQgqxFz`5ie{Vo z6v95%qknV9SO#cYXj%?x?Mj^&XbCw}NA=Diyk{<(93M2)$2{mnq{>OBUnM*g^ z(1yjdKQ>HVybQEV4^Mx{@e<5>4!U=Kv#^Mq3%+VvDFwD3Cldf+X6Lcn+@hcp-wd1i zaCFzk_g^I9{fIWc+!l9U#K*V~ckny2P0weKKVCUd1-`?g+Plh(fgf6IX=M-spvl9i za9JfR`ig&$XkNEReldV;$p=rek1`2}rEb;8G)MdWWw+OPzN54A>k~2n&U+GYt}qnB zaOo#81GSKUX-V!#wbQi^7h`w*4UAovkMt2+Ge3~1Y4zf5z6}IzJ{`L=GjGVk9^HYI z9nft4_hUQ3wUCe-mvG(I5DpS+aYL2f!{u51-YRZPCsG}+6AKN!K^tEk5BjEJmp>eU zSpyc5I-fbb08>yl&r_PokI$dwlj*;G@yg(lKk7U~DNW((oUx+1)a)FziNSduOLE~>K1u?3A&9sU zG@r|vKH>1l<+ZZ+cdbDj8=5xkVP$ymBIb%9!kH6QtnSV>tWU(K%AK1{%a%`jE?F%m zXe%Cz#3Q<=oxy`z6P zezd}rbB)LB*#xfX;jCbwg@zw$#-gA=4d#sv%Nbj$EAM`p085o_1Q+Yo%)NP) zEJ3pnf!3;rJQJGZ7Gq~`wCuVl*&AB#g#(sxbqcYb*eohG13I@(&pw3(J}V#w07zlGkK$Ds2UU3lOZJ|qNQVqB5E4zx8&Hm)`})sBkz*6IaQpmw^~ zvCeUwC!4+L=W05_WcI(Aaj{7w_kivt1>q0jJ^sT(8O9>rX=z|vhR5TZj(J*8uNMff z#Zsdu|1-5KW@Jno&5wR0nk(&Ynf%N;CV6{}W}nQ^Dx;68qNppB`CK3e*9Yu6g(V0Ysc(f0_p4EY97vHO`DUKg zFXUWOVQ2NO*0XuYWnBP>CcmDHbeq?y`GixbA2re2uAhsEX-P76d;hGo_!jc|Q=R5d ziCP>0!n4G#tZJkukCwd3aGued-K+&&clUj9eBD3upASM#WcC3EWQ1LcH|ws%Lgo zttqp0Sa0NAbW^iLKy2EX78r7e_t*N9wDmensn~R`Q$uLt@xBIO?@!g7RE4@M$-^M3Tr)Wr4A;P5(%!T7$^A&uk$sMfX zlZikrud@%B@D5T$+hMsFDQ+-n%K;aVuvG1u@$`1Ph^+<(-(-YUpG8o5EfhZg4y?P{ zhr~}bKB`83ruZz)vb7y&HPc;mTR?T)+ol#XLk0{JBQ_A{sW>_`IJ$2NP zqHB2w7tGdD>BMn={iG3tOfi}9)Mxr$fJ2U*XS}5YrMj%FECj7 z$oR-OCl_7(1&VP<0V#Eg%K9<&ZtG}nB4q^>rKY|gD8xRl54yhPr{`beJm*aKMr&4$ zUhFNpn@G)@iQF>v77W{tYr+J@jeGEpr@LG85g}_Gzh&E9@3=17Pc&tupKODc^`cQ6 zvOW&V>q-hP8b>`z`#nrh48WGiO1yWrxLwFKyp2dE{kZjV##z&~k+v{!8drasiN(8u zvY!RmtS@g{UwwQ`=*&HW(o-~aQNNi6Ttah$fC`~Q$4}IawIVo$$3GdxGJkkpPnz(q z_x4mZXX1oZ-Qy>R1Hydzs9{=IKrvPkA@l!TOfI#9*Q?)5J3p`;P*(GfjUd+yYrW&$ ziF9{~_B#!XI_@V!<6;z8lel}EPEFxto50&M(P&+qAd1=a18U+Q!s9Y*m-uC`@EY6ef>vw%b;EK zi0J%Ww#u1n?JVlveU<*MFex)x7O>xwsK7z{-q(gLo9!2Z3i`rlqQ5gwJ1Ju}zRm~Iyd{Z=p^yB|DBO35*Bh`+CYe}QNej4z7<3C(Vy zuifvDmI!jpNp}y5qozHZZ16`Nl+geJLJp~P<1&exe>1G`2GvzQLLcPNMvusD|N55K zHXaznT~eKFlO_DZS$@c?q+! zs{yjBpD#e;HDh3p9IuHXsjFR!uvRoef6xWXY>ypwxn;3gXr)5P+6%k#nBQ%N8>lwb|a1zh7Nc(ulGQQ7zW?tH9V~ly7ugu0p zpTv^Vq=Il644tNi(W7dBR7wi)NX#qV_NFQg+4Zn%@IFFMqu{j}UwYej7P7+;_N^JO z&%>LFkf9}I63HJQ))~4#7BD}X9f%o6csjl#=Rdvek8;=tYB&$)8N!rwoQMVbf$>}t z^f-eL`kMNH8sIN4;Iv|br#$~d6QWoBCCE@}K_> z!VS(X*S_P7an%YN z9uCDq*yeLl<0Coa6y;UnWF0w+`T|+&8C1oby;TeHl3<)#p$P*xwljG>eWs#0v&YiX zrPpTouv1P`g>Hq-mS$VHmz^%Uqpv_~Wv$RcHmo+%1spIBKkPfYZ4?pGzf$obW#G~x zfxo~`EwO$d=g zG*mo(>^6D^k9>n^qs(>V)jEU0?V>-sn`<4<(@e=UlD1|Uron<<5fnk&%zhwvR7)w1 zhMed1`tI61T^S-rU2>}M0%*o;y>N;)(AQJ@>H=(_^BMnINT~4xjB;h^l;RR`o$A)D zYq_7KAk6Y1Ou-#`!F;%hW0BR^RbUOB2Nl|EUCQR@z9#EDY6wB5q1HcHa?T9dn1F4t z1+A!@o)$7Nc$!n9CHJ`&4BUjn8R^Rzvy!f2J61`85a=l?x@-)(4;bFjY2^rr9BJJ5 zasJ>EFKMkM4r+ZC9-bPCJb2Ency42!AF&oCkZ9Dj(Dt0y==GPoJT2ZX`x5wx1ibFT7NW8mHfZc z*R%wT=R1$rv`m}NAPp<`cFpc(%@KhHRuKbGGK+eoZ`beRsyagaMyhQmh#1oi7M|2e zZ`dJg37zxUwlo%wt`0evO+bg#Rn7znrB%Hx?3Jq9H)^&0T(x9ammNzgo)ecVuR@`o zPRUq~n$LolU6azxM^x+TZ(F>ea_gCKK@slouwcuzW+X$JFH_vNh)>hzcw?2pwi|tQ zSg8$7-1=hK2qs6*r0N7=l&}O)W5x%{uxEWIXo=MP9^It#g1wawwlm~&ePo_kSGaP2 zuofw)T#9{*31Kq`pxvBR)rfuiP0iN>MJdd}%2L76Z>2*r2igF1rhp3D-~EnVr0xv3 z`TD5kkhtyu^|H*QUNIQ_?&gJh`extO7=TaNo#K0)r}6;7YkTEP`UKbyG;GjSb58xikCkFFm{@GL%JzWHPd?X3!M z6Zc3(J``u>9{RW6{`&X7{pY{``G3xR@z;O(*T|_kyp#xDI1l;C8?;$_4Z_pb**Dky zS%j>sAy{#}%-UE3M*vuhda_srt>djDo2;!~8EvWl0~Q7RIDQ96nYs-O?as7|x=WlE zTqeh`flV`XKI!FzuAkQ=HQ)^JN#lW;whpA5JW#FiN`j&$4(+=$$9@+mQ;8bTDbmK9 z$AlzHN$f8pxG1c;TB^_v(n)Q#aJ97P4VxDTvio}HC^Untb`Zmh_$bB;!>CHSW7VAY znP;6I_afSnO_|R((!n$`6j`-16?K^3A!-}{_0Wa0BoBXbN(dQ6AiXkH@pZWuKQBNW zkVvwL4m1Vika#lZPd` z3zTGWGXxHg7BNdLtMEXQjDkhW1gGj0+=Xtd&2eMlcI30ZMyfwyZ+&Zg1vx9Vk1q5S z#jD3kxHy}_eY6Yq1$05Evoqw8fK=B%a9y1@_~-9Fto7%tj26ax@linEid}JoME>X+ zy-ebP2b^dvp7Lr{Hv56V1HC0h*jo5tXls$$S^heJgKl~dXTV&ohhHJ2*t#8bYfGQz zJ5adm5rl7{LD_K568ATloUJ9tymRfk2cD(-zsy9|h0m0uSWRQDDT=sdLP3jk2wwKI z8$jgBM#yn>b=MtZdWFzN-mn%5o#WN_?eKcmW<`SV)K+hdrd5*wdA&Tix>#D06hai% z{u4967vm~gNU(TlHBhn@>OH1L>%nu6X>iZJ?@MTh}zly9zj&dhJIr zvezS`yj}JS&}Uvn=ze+S&$|mlH=XClu$}^_=tIj4C|B zl1U=xaI3J-EW*Vxm0pn+jg0tMniai?aDpO(8|nKuW6*RgSCbOzLxP~qMSNM2vjws{ z9wtP7BO-`RZykw5Pgj>17HcAj!9DbZd!0-kQc!CiMxtgvjNe`QuD-H*?BkNh+XLvy zR%+2o(NK5*lvmM?D(y%VCygApz-eoh)aVP>=-4Lnb6Q@IM`j)65`~|+{O^%^5{Uh% z<#VDeY>oHET+~x4G*q(E%iB@x8#V_dQG0U4S+Gi2&+lZkZeu41gYrFQsgL#V&ti$DS_wFNesv1279(Z_^b<&fqFDn;xLz=d zVDe8wqEV7>q$&1I4+XFl!8>orlpW?$w?U&bj6oNPtq&c;L$gMI!@Z?DV5Ulk=h=Ro zHX&p+$-V6&9aJo9SM-pN)t#A}e^u{rfV1m^9AVGa9p#HB|t2# zqmPnEw=0)Gb*lL19D$|4ES95EY zmR*NYga2t~w}yqgB}`rB#B)5tN?MC>oa)P6ku0nT#p!q)t{$F4R8>}^)giE{)>}f+ zFWcS-XL=StOP0q?>=3oe18)9ORrhl4PkcQjC^R_F*MlAuzOHm}2CnNAo4?=I?&DvJ ziiHjlL6{BvIP5}&I!MdfjNLFU8$3S6!d!qIPtP<$ZPEBSl1qjC7AA!TLe8aW+K{6) zzfU8n+_rtDd;5qiQR&_$v>S{?HcvPPG&^so+Sq7vhB0^?>*dBk%P4hv|DZxkt2tYLSK%dH9oN z+`yQME#!z>kA)CnuUjDR8PU;QyDS(%%J^7|+8izY&FM}!RH27+p4MJJmyDCn@BV;Q zT|poQ8#(+ zZMWsx_m&jNLUTK|qupo;U=T5DonCZ?-GT(1tr8K>Jd2_B@K0B=cF#}GCTwWxojuzg z;Y#+~+N+0Q*MJir=LiV1%{aYkgb3cUK|-0u-iUW$gZbs%myhQFZMomZS)vXoj~5CT2?#y&b6{C*PjskaNe;p{TB6!9 z(rKC_4d9-c!=v;uBD-F>a-owXU>W7g69cArcbtB?-;u%O*jp>goqW73D!!U`E&P(sM z9(t9x|6`sMDJt3!rBUc14H6EmhSK`^d5h~0MhmoiL?L_++(yFSQr;qa<879952AeQ znYu_l_AWltv9Sb2i1MwhkTth%KSYEan9cjeK+W zukq32c@lvOUMC@ioGXX(0B*5boD_uW<2QeX`@qT~p5BB?N1UtQ)s5+KCL9Ku=g<1S<;z|f+8hVF(+AFJ$ z&4KeNIFjY?O)}DsD;`V_l_$=^|8NJ39;`Jn(Pg!O3xl7uX2P{e;|_}3Gf(+5KyT~0 z0daM&j#Mnc;TXEO;n+gaDwP}H>}X-mM}6PTikPsUgsj0)>(E~y>?6b%8ce6!b3nD$ zc0HNZzveka(MQKArT>%GG;Yd_j!d48g#m_slJv)8t!){6gbwp>Pz}e4jT81UrqXe%POC16?s7LxK zksxa%hidnHZo}u`Jije_%DBz?E+wE{KHF!6?ba@)dbRWn9ONerrsjS%@brr6-Pj@k z-_{W;(II!Z2l8xw&!7!vHd>$+1+hkP^vu@vO;=yOYqR!xY)LWqL$OP7D2q#l`NEIk za-*}F0QCU;O-&)Nh6Xm3u&MGSj6vyP!I#F?b}CNZn{(W40U_9w!)nk<)%vS3A(5ZC zw#s_E<91IRvDK8j1?8R_g5;w4x3DL8{f!X8vy$o{DbQ13Klyq|gCF^m^yW?+h2fE1 zO~jWZkl8>MTCW7xg3HPPgatz&hE4R4HXbIJVxMVz`g~U)ceLk1Pv0Z@gKME->wJGqfcyvL-$KtK!nw>z%IEcu$)}I3C0zI&y_9KS>vZEbBwCiUWvHj zrwVUssHsVJIep16P|OSMw=r)a2FM*MHOrrPPVjNk)YKOj1t4ka_` zZtiP>X_%YL7$#sFFS;L5hm|=zfb*6AjXMNk#Kyhu6q<)6=bPj~Iw(i_+-?3a9~dJn zEj%=D)LR3@*=%Y>ZLQAS2mpm^@fp6PJdPiMgJC0mm*olUhvF$kV9B*`AY&84j@8sTHgEm9f(mv+fuGd1+yR z-cK<1T)(E-v?CzjYZ+lr=QTC|_i(8Jr>&-tAflr>%um2l!^%K|!JV2uD0sLB!D)Ge z($KHXquSP2IH^CE)o8B62ME(r!%}LP+t?$4L6Ngvz~{|ud?4~B(qhf)#A!ZHoGg_r zKa91_M5n>(PGRNrvXue=ML@d0>WGiwIAA*uvyULz+-h+k$baWyNW)j6kTJ}@6EKJ? zXpRY(_{Bhu0S5^t5{9t9`prUA(;-f~w{yR?0Rnkdwn#J)=rv+>Q*e2#ae}(k=B&P_SxN z1iYd6X(o)kkZfH-N61*Bj(EO%)SdG`_r?;lJ6cFIW>tH;)>5jFo8JhhN|o*>-9sk&doig`vV_Er}TzOf`eGm%u4N zSjgCWzm?_vvEF|ev+9AO7G0IiVbgQF56T$g>UIzVG3t2%!aP3tnSXc&^U#b{Cyl(? z71ExF&tJh_E-Q$VU{{2$d>qjo$^QPBw=z@r_6Mz@nG+h)F^~9>eQ6NHfCyI5=h#WL zB``sGIzjM2EOmW<1zK;^#+~dEVt#rC&usHj>j}V5w?*JdIqxK$5NO43YGmlq%Gl@c zYjk;$H>w#1WyIPh0A0;Og|c*5?Vf0$2+$x9oLYR)WwhLCXmhTmo7GwTdwX1*Rb26; z?E|nrm90xK2t4~i{J@G=HHOA&`4f6?PfmK4d3(MKJ;M}*3j~-3M^Gh7OQs+0b7oP4 z(eoUBuDk1S5DL7>3g$B_e#boI-LjmaTj!GnBieDhwi`6;UH}?XD~o2ay6Z28H?D9w z*@NYw;1s5%iD$*;&%VA_B#16<2{&g}@Wm}h!t&vJ3cH-^wT|f_2D6rJu)|kAKMR)2 zd@XzqyveSH(81{r4t=#`!-WfhGO`|^KfQ3$51 z82t3dr6h~#UMe4Qp2!Ui3crGu z-97*eo`wYSO2-+_0?B59k$D+kaRSBCvRZALwI3LKt8sD18~C*dV&0`3+1nx;M@ii}rQk@8rJ;CkFeV%mS)7L{a&npKB& zRDYYFq3!N;S(U&My{4!4v^&DG$uv#==ixHHL7}i3G zwRtzzd}X|x#GpL4L~aY+SlMeJ9x@W4RRXrNpoI8?x`!DaLxo4-6O4wouqrIR#6WO0 z8;z=#%L}j}iLw4;ye^a#%dlJ3^qSnK$ z37c@FB7CDyr(F2L2wo$ICxpnXLec@qdDIgYB3ioz`Mk`rIL>4@|Bx~pzJAcM z&;Q7{*EgbyU-~~eHAA0qNXt}xp$M|HH(&A8hss>Te3Cveg-mrk`mvCs9jKjx9^ zDO~jbo5nKq>fIRO@J^jz&|0<>;Qoe;qv)>;59_h;5mfBNv{5FZG|9)6+#tjss^a2cAyYv?qv5*O%6HMydKlR?z&Z%>ByvjP&( zus8T%%9`iEKmBFotdgX>>>UGHA9uMx@EBQv!*=F+$5}cuvh7=1^We_sZR@LNl<=pEzll*&F z4|4mmaLQZ+D`&)5`m!`AIHu=u=MbGq^-C%ut<53>J#3)XRk7+!VXQT5BqbJi&U4X+ z1CYPNWyD2WDg6zgTYEwo6P>fB_FTQ6S8n3YQCtZ-YaOv$?{Yt17z&s4&;xqq&QBi( zn$qi;70_w8T#0xaU%=F&8M_mfckwy%tQmIHL7R``bFCkknKrxthJAXE&5GDV81Tr4 zY450wS*{c~>f`Oy=;zzj;q#3^$<&ShJj8%m-GZ^`yj}aRzh@kBc*P7Q&`8;AhqR^r z0og%diLmNxZu>iQ$9e-Z=*eD;LbR%9{%|{I-x}ncoV4B3nGWpV+MBI*F&^Py6fZW# z<_MdCvk_{BG{p6xJANxZpcb0Sp;st*t#e_UN#>+vt)Z>d0m(i5mKaD?hh$JN#nSQH zaBZI0j1||d!Zr4K?zi>DwsR;7L4{+k;J&OxIFB=j+7{BA+I$xs(qX_D58sd=hI%8Z z(DSZs4S1skp3X~GZXE&z;Gy*&4`6Jy3_y?A{(K-HFVrSdXg&h5X0mtitRdAG3Taqk zl|Gcj#u_429o|Q@fG&@L&=#=fuD5%$`g+*!p`#|-u|8jtz)HoIu46T?`h#ABfJZ~zYGSM~J8zpP&y{Q6L z`LG;WfRCG3cyL&CBn1E_QP%fqB_QM{E+O$g9|5;c5$2ihSCc*TrL73j%&ujwpBxt37H^DwNTV2-kh z-K_Y(VjN|l`A>RVM<6Iq)N>VE!bx1behz($Ap*760`%psg&rQja<+RbY_OpuglikK zu@sHb+7im%Z(Ti<*LQN#W@f|I!tfXs5%dga! zd6i^V_W2lXxSY?C0@HdKR^WT=mu3h2EU4Ia6Wa^~BuyP0-q?z3cIrBvy*&GVE zv#ys;_S zYjGnE6(Xbko}&4!8Wpt5vw~xdBvK|_}|aL z2{9*oHOTyCAUNs0*^nH&$d)sjw=9HjUfeZ0;i7dL!eFqW##C=4S^D?8X0?nDLRt)5 zFvySe2w=-5EEycfsRZ<`+Z&rdK_{mQW21u;ALhE1>=3??3isKRkVaL#1DwG)mo!8 zYDN+snj`oJ*Lc$>(y%Lx4^`)o%~;0j0oiB2%TIbWPyR=H93JO$rrjHAc4ChmAx68F z7|JLq`8j_9`_3%QpG)u>SXMs!Lv=;ZY9E2JRExg5EJOO@4+@11FHw?kN%0|0qfN;G z&hvJ6fY-iiMy~P@7y?_9{|wlK50QXmtzR1pDy4u(?rQD7d4O0!_><wbOoZAJ2VFEdYbfe7eODGXv-7MTE^d-aqX+`D^jtgd)F z69ZYT=KN%xSuq4ta|nf3d-TxZ?{)%$%6Zr#0AbO$bq6`xbONX#hDO%_N(!$F0bk+H zklD~p%(e1Wd>3O>#v1z70*M^JJkSZGKGt!o3 zZNx0JEs_d}9%xqF3;3X18)3#2bpkD1E%zL8*;s@DFSc8M9YOEZ^8p?7`X5GHL(BC! z3@Z;4!IIjJ7o@{iLYO(f(Gx*J^Q*l0zb*#GeLuPF@POCXyysjzCtBX z4Ozv0GZ;=69%*-Z+cfiYdhcyTE%8A)45>;IgxZmK2zXF>Oqf_Xe+t=Q!?I=}0}FL+M2Kll=7k%1J4aodL>?3}*fApZ zb6h~lHiDF0TV-bX>9-mlr*sg_8`CP$2I-!lRl^a8pa@f&tV1Q-l>;JFao*{CfQMiD zWTL_?zv)6qEYt^#YRAUupkLUqn&OL9HtfBgb~^qCKohPLZ4|O zjHp^em$-S7fD)IHg@zHuy~FuX1#ty>!@eA>Y`6C5DHkuueJF7-)+{A85D~*l3>$>1 zJEv~*0Z3$%UgO;j@T3ZrmM0zgku0I@zzz0xv)IHJIX}(~0b?vmT-w8=Atl`|TFUCP z_492?g~DV$CTOpgZ@3t#Wv4L)^pcQ4ZAy?V-s&wCJ7|;X9D~M_-Lr$%m=+KOD-DKw zh@Co*-k?UH%&pZ|vExbQAk;A|+Iqga3vjs0KS}Z;Mva_zLK3y@gK^A9bh~HF>7H@T z#q3I*o#n{1x8^9Y(-XaO61Gf{+lwqraEneb`iH76M4!;8a31Nm^d>3IuQZ-OUd{lF zmpK*B3nsBtE^lU#UX&0b03xot#Mn9CuVzt4K=By=nvA!=wrhXQJIJ2fO>nV>T;u|W zz1GlX8?HkxQ@vv5-ef$ANI#ZMicR;C2E-8B7>?>ypyB2S3QpuQn-j{=s@Ra9I8)me z$6X75?0~MEd#_)E>>wlPnHBU?V2d!geit4yez5@p0--716)w3cbZ&ClI%HI1>NEf_ zC1fd8_^`NDc7P(BgL*oJP(BgST&HWtdSf`9ewt~XUaYYUpaVQ93xUFi<(cQvpCDSG z{Z^iRxpYL~1c;Y7u#(=-z|RvT&zRS<+s>$qnTTwaaa2lR9C3<%^LpM-2xJ=e39vy1 z@cYPsF6^0X{~h{6f6~cXEm6@KeL~&tlZ4@Z66na)stf#$Sx~W&a!08=bpnp2c=|04C)oExugEegGR}J!KnEinOW(_w|Veb0G51hL09sV(GPJS3-8mJC#` z+7m`5k%GmMMOjat>34DfP{+z|G|*-Rl^5%rq_pFcE-@hI2%Oj6{)n=r4?X@Pe27G- z91L2T_+Bql7o5eJT0+#6s{RTpnmI0nD!y0sTFV1RnYc$gC?6VQCH6mD+5ALnk z787bEU<*37w$d4;RKA=gEwJ{?+_&izHcvPUlP4W}?NM3|IdQ?)&pQ*SyRnyZWjzo^ z)&=zF4X#c1pyVma#e7%iNQ2;TU=?RGgadNXiZCyr9z~n!#fb!tUz+hfJ&tjADBt>c9ov6=s8i1bNP zKGBIc=iq!^;%f`y*-8(A^Jul)B#jBU7~@qjZ$VEP*-|U^A?5^qa=7yalx?vWKpE;? zy2yGarKZ4#^q;?Eu6gp@9yxySKR{zPv%Gc|^m03roH($%ySHQzNhGdA-oM0b`^fs^)@{xcDHJ)t0@TX@HnO8onXuCpQ^%I1j= zZ}Q+k72OZJ!N9ioO@ejwAI~AmI++401^Ke>Zdl)k^nFLu=Qpi0+_}||>mkPIG;$-t zb!;;Yb7ZpYa&fDu@j*zqN9fAkvX?KRex^K6Kq?i&e5_}lvNnZ)L!(`H{H<-xV| z&|`_5^S9@ZL6P+5@2YcYtR_XAib=Fa08b@FDL0XWn6RO$m`I}Dly+3Sle24zuvq$h z;2fda7bEZ&aPhW*$m>ei0UN8{3f>(pG9`@2Tx)!F)=*GcUx1343$#cHx-0g1TEA6< z)1QC)?XQ3P?|+kf2PsXuR<~fnISZQC1X;xA3iG-IL(vB|nv8SI0dcPDB1*;+S_y99 z5bWN*Tu0U*?l1&)eDpkMJvwpgn2K1xhFUTGm{7Afv@A|F7-|ZM3}d`A>Jf@|>x<^M z9$JoAjGL4OD4^Tg8#$D-38*wKw=tGdZ@MXjeqAaWU3QV1XGDs^05N;aL4eR-QU`=! zBY82zm<(=?rsiA_Rssq=fuz%+p=8wQG16o7eCRt1HdJAwJGZ2@a~Qu9V``5-=E^Y^ z3k0*9*3Ec%o4HKWdyNo{A$)~ys&PqE|KT9QQ!GG0omqGL`6^j8VI-f zAfH!%<;eucNPVQRXi0`ML&0(!*>~ne1AgevYIqf>`xJ2>y z)R-Mu!0GOOXlY^7%!iofzHWuM*<#pkWB>)I(A^XY4()(YxixE*% zHv+@aW_7#y=tmwIXYeBPJ;q6)MS5Z*#{cfPJqaUA;_$qnJ-i5wTAk@V@`4ueMPgfC zMYnMm4~-=AYv-Mo4D{G}Tq;PJVjZ4Qgo&4CsV81IIUblhYFH()UROw%IUbIh%7|pg z2H|vk9i3Y;e7Z}DVxkl8@XGSI4YQi1U%0d@5y#cjovf4FOp8DspH)l|A27Ba7+o=g z8tvvYhyS2Vjff(}mwYHK<%HL5i-IN5Edb7-5wA)82ao$!)0M7s$zu$p@8Q`t>OaNI z{g6ans{)aCC8HqooTJzHD4o-Bv}Bid;H`34tgVMJu<(UaAw4;! zB@=1sl?Z=1vuwnEHOU8ceAqk)_0^;YF(kI+DyFG91ZaT*)$DXW`y~E>PQ0vz6i5sG z?{1-iV=)M`$x?$7@=ISW5JTF}cGq+=o(r8-IYEcpl}yGp&Z!q^>#n+*?S@n#f2v zIt^C}gK+G*MI5SfTDcueuPGeYDeenP257UiNVlWxVp7{n9%WZa;{ygEYFo?{m9tqd zpQ7HD)F+R$iIMvZ534}8_xo+&BT%UKh!9t{c(G(VzT4dg`5OAJ)rN!1i%)spbwE2Z z|HD=83W>8+In{#4delIrxeMT8yD9wKwr^BukLzOF>5!w8eTPmMEGU7bdT?p-z*jRU zd1e`xBNYc(ie#VZYg*9hJcp$(#>{4%T0Cg#3XVY%MTFBV&7+e@CeV3g#iM`#mB;mkV2?+1v#l^~G)~2xRyINYE)vnd^Xqk^i z=Oy|AW-9RJPQk#o)Rr00+yVmTQz2RzqF*JcYAhismf|u{4;zJ$0X-^%;f7phdd#CI z>A$e}60>%Pvx`siGeHilV*PMV;$Z#t9yHY*qBp1V7>bXXB z^3lx{Y-M|XfRoS6;Q7I2@d+B`>B5H=8(0bB0T|laJ%Uzv_JKeeTxXhXA}n#M$%5pB zWn_^5In&JOuo6Z&7K+sIVSccwt}1fYgXl#@<&fmr-|N;_TE417&Y|1fa76cw`7Gf( zruY|XJ06tGL*+`(c(U}{XDPjprrd(6`_*d8ep=ksOqNQXzju)N-Q6Y)5h%EZGM|np za4Wic8HB);>}OAz8~Uq;_#=iR)qhZ9-MSZB{`_VU>rW_l^src0)~w=5Q=}wjlPuKG zv$v^8GTTgyKwR0)3I-de8df}#qrCFrGYD3T5Fz#NG6=JaE}B;8nw^KK4|h-l*E^xF z^{QjfJ)^TKsH@J1z+V*4!%M;+TXx zbsHX0wBt#*#8y|gJ0#!|j0bY%vBrt8Zk)=+-AyXl`Q%;V&$z(|-?|605_(k!5qVNF z9O#vJx_30G<8w(O(y9e1gW`I##B|xPF{rd##h_B0+}LiW2iBbPIT64CID9Ly95+;ApNWTwXzb`@FO539VhXHP@Lm z2J~TlP=m@QhzO`Rv&m5ZsJU-jwEhhI0}^O-gU{G?iMO={@l(4lC-}_uQUYn4wV>hH z65(<(dU=GaS8H!QpOK`OB{-7mLfO&Q>_{hSj^n!+7JY=~!moXI*aYFCzCI09f_n-j)O<68u8A(8+}8|(h3vNk)8$br z-sr*Sw24-;jVg}lC`iX1PRJqh7~>V7rRqWssAp;_pjI=EHGy{#7N6*h+m<91m}S4;&htU`9IESvoG5xu$u3O#$a^BjJx85R-R9b=`9-}_aJ z0pO&wmwFKCJ@vWiO1LJ}c8S*tye(}jBNRQJM{)m&)zb;Mw&6C6!Q=FH$ed@wb@&X# zb{=lYTEG|5t3K|J5NlObqguP%M+rXsnM_;qL=iG;XoMfR9?;&THCOQMnGgN&nizC3^Zurb^$>XQ(R$`%+pACuwnxMJy6 zkD-Q;9gWNW3;hUxGy43jyN>O18zVK3~b0I<>cT>kXPaXbH|j_f!2do5ty-Y9hy!qCZy3t}&ren_%fdI&f1P zI(N7{d=0AsyEIa2+o|5~h zAOzzdN1eg|Zmpk_ulPf9nWtyFp903epTY#6|?`| z+3*Kd5sD&04j^W7r=J27{+B7sD8Q@rF`Z;XsvQ@}LA@=9oAmU9L)&V&0lqkdu0$8S z*;?S>|l#;S*t8Il)1~+NNQ?vK|r5rPS_= zwpTHV1658JrvQ+O10$TH)IUIoFB4!5k$ztrY21cG!UcM6k6XY^__ZST^1Ke9$T4`2 zMGakjI+vXE&0_67E%5@c&=}cl4J%89^6NS(nxu&`KWIL^Ger=$W|Ltv_hdy8Fkuk^ zaBwc!Aew)l5=^w+UyZiA*tZl~dJxc+D{e|YBz`aJ3G#yWX{Y^Q2gzXrdno-WL`o|& z2fF0E_Dq2N1!kF9n!>IWLpHKyU2cHc-cl#cgD|15VPnuJ=LLyV$e2 zkpY{7z~=WY(e!XpFgFu9b{4nS>A77UtIk^A4@OuCGcb(X-f%}eA3eFy($_#QGv2k1 zsCU(;59R*;8epw%Y^+eg?XOx(;OF(UA6Bmy4O6hQ?80*}<2v#Xv|1twm#y#}VV31w9%D2Ij_ZjDX)R9-pggS^5P}Mo^8$cAm)e1yxlao5Ar10^mKH?+*a#DAbpf!j z2p~t?YZtKai0hGUOb~c^PrHrE4y)^b(t9eXOkTpp4jOaMk;n=paSSw5^KD(T;84Hh zvK(0bHUeS`DFGyOu!?h4z2f;^`je_uYH!D#?T{&UE-WS=>o1<|vvw<4#N#lEW>)oY zAqA3%nvIDAZ?tArk7JPf&Uwtm*JB4fM%vWCy7YuKJR1F)805N{vV!SR}I20>4f zf?%yZkv^ZfvhCbULnEQ=jao_e2^Z*Vwe-V#{m7OGR-!#?pN$^@bl}lJcY*P;rjJPw zaaRNSwsMzu`jQhq<(+o|d3W$(zR36s0186hY`mKjh`qZxWS~4qE#q-sEm3H~62=vV z!;d0i3o~)+uHi?SsoI+*emO{hvRe9jJqWft&kxiHKgc+>K8pEb22v1sp4~j<^@ltG z$EiMWyz57Qv)%7OB~Md1qc!1o!{X)|=#N zk|f)iTS??N!eQE2qg+A_3sp5C9*D$afFzhN3&;nK3bi1vgBzoMqUVUIxd(EP*Ten( zzcs3&(wxRG=Ucm$1>KK(t@xiReFM0VR%Z{Y0E%5;1g&LOk!w;|fN}l?dl(r~!U#ok zT-4X72;V5m5>&n0)?NeX>gB_;Y5$oi_atyhsTqUU^nRds89C(YGo1;u{+f1&KoSo97}c3{t=~ zE3`c59Z9|(My!Y>P-4yV-y1gv9fkhh@YOE|Uf>@-;`iAb7d&o{-sabt`Mp;+pBj~r z(e1t?T)+{cAjKVACQ5LGQj=46nO*~Uk zO9S;F1FE8JAwsptalo!~S}Y7x{4#=}4&@+?95~ty$3ibKG&t7JHx`3_gl6W&CxL*P zwOaY1{z~VpMlZpEc-{jMe>TD%%dgyM;V$#B$SP- z$pafO%?yflB%pg@qT;}+&sEI>>b34E)Cwj*6(3L9!Blx`hv=AFgf}vwi82l+8;gHc zob>c7v|1EADPK;VHOzSDqH@zD5*8hf0FLi8zUiTJ;upkk*?)n2RPD}r>QyOmkk16)69cyx7{aD9h)ZZgD}@YZLl&J%}&Siap~18?}w*aCV#aWCN4j%vZ!J4ypBqqADS8&0XY>+=h*BWpqO`a6Lm zgyHi}hi!zRs}Rhet{Gb>YZh#1UVm9yc4^yTKv{h63?Ao^aT);#15_Zb+W~>&FJ<92 zXov}EaclICo1r0C^J(!ihdP9}d??Ml6a&_gm>i~PLhKfvjol~5+?tA~cPLzX!ensK zzFSs^TBz{YEa+mVK-C@sq7~=brys6K135rOe$MHsL7$%>Y$K-O>xT#NOj8Scf^4i|u6I{pk9|4AQ0wWHenavwMI1&5hAvkm|i z_VepYnEOgNdgy~29woBg+VPs+#6ClBA#-ciXiwuQ3?bYjQR6#4nKQIHe>#GG?debD z^vX9EsjszI2CW#8)IY%+0Og${qpdB7Jk2Tpmp%7AP@YN6>4rZ23Ukz%=c^-5n&1lZ z2=At~Y_`7N2YOZm5T2M_O$64Ht-V<@FJxs`B&0`TSSbZdNeie&(~eC=Zhm?0Jd0{n zJha77&`;vMz`X0?IVo+5Jb$HG_~kiTnjLMN65wl96H?ZnHSj4SO6g!B~mccPd$2d~&43-!4!?hzl;d=B5;i(J?blyE2xM^p3 zobqz#IjT@PPi1iBLnyD%ozqGB_A!q*wW?9$l>n&CxcA3tlybbj(6qS_s*AOyWW4U> zvcU$TtUX(H_sn@mLV{6q^IU&yIat?Ri_+)M3VJpuKom$oU91WVO-GnCC}IJi~c?)HImC;aP|15%G+% zDrq*op7A1`ZSLhqqjO?$Z`U<~0T`c-K|G!Z5tCxg^7$Bq`XLL>^3H_!^+p7-(!syY zt}awYlY98Yq*R9vt`ml9ji`2YR$To&66@Kk#Lq$dnoEK4NHDII(LA86Q}eaoB^fTm zmciM%i`Pb8F81{j%#+Y0P?i+FrRki?Z61~Ba99J+6^=(sQQM8aAr@7{Vk)pq89^Hg z1F#(=mG-gBkV6FmPM~;oTSvpw()jNv$%%H3i~c znt2B~LMuRUsUuF9GG5}<%;D5aIw=lPQfTK31WwcVKpt*tg`pwir@K?SJ6KmMm4D=9 zjA~oa`vnIj4I-8gP*B;-v2iYO`hk+>wbKH(LOqrKV+RwgN@ke-m;e8_zy9C<_~S4C z`d|OsAOD#D|BwIo-~R1?{m(!C^8fs=|M`#q@$bL=opMU$; zKmPK6{Ow==`(OUg|MBnt{>R_{@_+sD&wu{6KmPgSum9oy`|IET_Rs(Fhor(z0HcZ3 zc&;S4(HVfhp|fh4e`$VXT-AD5j$mr*QIG z9k6hM{j%QaOk&4l5=0ZOwFJP%gR4;AHP)oCpi_haoOdFt|3+cXVU>ADCaa`ZD+7QO zE){z?l#X6_&t12?o$HkY^{0lpR{Wte5y`eB+5oFv!VFO1hVyP{-S=0;l8oKz=Sbxn zVm`u2c?GKBiY)N7FYyX~kxLkqWs?l~G!bp_OV0reOvqDBvWK~~Em>)zCXD|K;JU)Wg;eK~u57oEgm8Nyd3~UyA3$4O= ztm`lh-1>UJI4^=F)bpYO*U%Z|8{h0a!S3cf6~d!WcwFKR8v(SrA&;b=&TZJQ6j88LCET_86|%2#Tgf)sUw&_a zC-4`NGrLt1HZo!l)Bh?)!GmDxCQC0(Z?CobiXP3F8${fA!ieUjibUYM)jACgeK#vG z#z-%=I|i5Q)fYT$a-jkH)Z2pJW#0zIYt0gpk-?_a0&J(QZvnVcOvt$T@yrSsj7wTY zT*Emeu6l-t_He^WZ9-V%{W9#U2g&YDHmmulF?#hKgv*2Fc(I`OiAkg{QXr)pQV&a_ zqr&G2(RI8~DMoBb3U#SG1^r6jI`OTd?CUK3Q25++#!3c}OQq_--`qBj{<8S8#pAcFLw zNVziOk7kLLL=e~01B6+q1A_LZ$3B>RAHN=mj5E%6#5P}dN;tB?)ij_bg`~l{3%cIJ z8jv%jJl3u%_%6BOJYULHRJt?L%GL&B%kF+En*DN*L&Bk$TukLobazXTMESYjQo2FL z_2yumNnQeH@9=q8XAOu`H$g5gTFKyy{9U*r1lSWR006mp{e@n?x=RjN>!tL5xSK-$ z^cWS5@VC%PCA9jiUrTb7F1SPwmCR_m`gpj>k3CEph@^X3UTD6{*ajr*$dMVNQq%C_ zq!C_uP2b{2p0EuWO4v3D(1z{BP$`M=g=KqcOeu0IRTj8vZ5E2xo}7I;V^+4Uv}hgC zPsF}`>MkqwAi-~`bQ-vc z-lv#2QsaTyqw3+4c%=m4q?apYPFnDN*mMuLM|)nCOdvp(f?xpbSyoAvl|F;2RvZJy zVo%$3gYiHJ2*Xw{cSrn1$$MWs!PJZVC8W!FuGoT;hv^)W= z9G|0MlRY;bVU{aU0M09JNt|eXyZHt-KT+67qS((qFutze5v@*9ESOrw zymCNoNh}}4ED=KJ`wt_e;mz3KYQRlarGk^UsV^A4NRR&lqm%<6JfY;=$H>65PmoVq zTJ6G+MT;R8wPiJ2TQ#9ekg66d6ybofF%&VkDuoW?nQ=vNwqRTa3!8!%X3`EjXJrhfSuBG_JleWSUzZ= z5Wp!hVA@F3`TZa@$|Jk-8}v&U}-EFi)To zh%g72vshh>>HBSnTnpsY;m+wyha{nP9cf&T6eH}#cm?=AB>QM9+_}bajFj-8t*9)u z2l7?pk!SN3d0Of@0D8r9LFohSL!AjdwCqF@#*5if;)us(A{O;c$u>3f;M1-^b1fd} zkc^Y`X}IzQd&M1zdtRK)4>>c-VLd6dtQG!I;H_3tJ~4mwORh7)H02z+J89WEx`)JwhQ3)qWeYRD{hINmmK^2D@B`f3D+Bpxtl{wrQVI#Jl7{rK#$%W}f<|R>6X3i5l z$jqVMz8XFRXG%HEe{`L#wTE z^6y+|Q6$`{SjvjI-GgQFcc%$4TmTeU+K(DwU1RoYVb-N%Nj23GhtG^7LM$P0-*d8s z=yPK6BMG&1DgJ-XLWp3cdOrA07ayRrmhOP{I#S8&u+i35tbPI*QqGsu%|Cr)aEHg0 zl$HvZ!JSQ-#F{O_@ikg(Zo5QhoZw6Cb=pEST_Wb&)?$!wcG<;7XI^NB87ZFBkVK~W zOcC<6`QtW#44XQKGHW$+pd#%q`aO^h0Cejq@Ti9o4hP!EmrtZ_Ytb3cn&=E1Mpsu> z0e8kV_Y4RKhG|J71aBBj%%U}txWLM+H_`L3ZG5x-tG((A>Aw@bN!&o`CTC zVHb-+9pxzq?iQvG`=r^wZ>@^GKVR7&Il~Y0JOg_Q%^YjhA=YxF5&&61roYF9=(i9k zPq3Wb@j)e90(K~#DU(rLHMIe> z-r~Il$;~jIx$v6_f>C02--%irYgIzJHM_Of1#HpZJn5neMBAK}8pc~Hyp@#1V+2cL zq3NfXw?+5=Nbv*odd6jhe=VuPa>5C+WCH<5O{V)6;pQ!pS6I;qNfC;Wqg)evPkSs2 z^01a)4ND}Wk@3$_)px^UN;<+>A?5#cOP`z&sNP}av(kdkfBur4MDg0>o(#JG5R~Fz zLTt$~0)VBLIZCZyvAt&(+S2RtXs0Zvrfohvq5WY!qwF^to z%v4;_V#_j3GxlSfjK!V6PE7}gcZ$NMsHzG*-;4{H4>()vv<)mALtB2F&!43ExfJx^ z5s7m!j)JqL)_&GDiW!WmTlgM!uU%8p;yUzk zQs4!@3`x6f%dSkFhZT#z7x?#gS|Ka%<7=|O%!&m zdLKX{hjZ>30gslrBjy3(*FA`L%a97TiEReZt}}k5&h4x{pAF}AM!X%BZ!OHpN1TrP zpjTiJ|2BcG!~ncZV6sN`#cRL?%*%|ia|o`?{sgHiNTT8-d_4u zBr1&mg5~yZhv+G$wf$Y~Lj=yQr~XaMsMo4-m;AG5V>#j7;`$?+3Vxw;%U!nkt543j zO2l9%N%QB_mq>5{ouo}+RBIuY9Lfx)Qse+>eXgcaE27^$CCfeq2W?r8G~0|;DYu4{ zSt2ik3IzO6+gWX)c)DsQ zjTLf|xE=#Sg>}zbRYTmk;c8QE_@!BaGVis9P{yMYtsQ4uT5;3pT_Ep%#I#v^5F zF!X+uqdIq5mDXMBwaPT-jGyOXIIKiU8(#wXab$E8bb?T+(d_3O95hh9^LB(JCFG;o zzLUvyK2#{CNj+F#*N6u%CN*eeeI(E+65F-Jg&SF+f5rnTqvg16g_aE(HBYD1xx?nX z8A8jLJM|t=SAP;wdEjyAViBj=k-(gbB)`36_VOC+1?$&VZczNIdnj1Kq)gDvszOh| zt9yio`HH)}y4i#(4|UO6s+zXMy}cuLfRu2N^A@gd6Ej{Z)JFAI=NYBBBjs%t!f5*) znIl{%^$H^UFI9 zEB8sSpw>7sy75#n)0AlCtb=2sb=z;#M^W<`0n8(beRO$Kv?rv-lqR8lT3ttF5q3mE z;H&{X*pV%QNRO4VXlw3KJFb47v_llI635g*dy>-8*iD7Yl+lG)nQA>V(2r8`C5(mKomtS`%7(1V<2|;J1{fv}O-4IMYDo8iU zW}4SzhY*D!g|yRe#4}`+aM$NbFaz{$kHy(s^G=>0BS^Y`{O(ELz@a{o9srRv`aUW1 zJxT`iVcm-ws5*;Moy3N8S!?088+RXrCl54M`K7&mKj~?`WsTTTJ$4G38+KSM!dSz& zD#kKycx)q$P;m7wM-n?nfI!t>={#gdtF2NAE2?Vo2{e4Rqrq*+=>i$;km zX(td^#a(&;x7CI ziZeQ%;!!haMHF5AnhkFgMrQ6P2f)J~sr88NmUBzU85S7XKw?xKY5MW`mAS)UqSc>&HOe@;=?` zK{zh0g6nWcHToGvexN1Ta^4(H&HaXF!j^c61f%Iu1pV2)!5gg@ry$RHWXtR<;q|e; zcW(8b>YZx2uN4~wjAhYU#Lx9B%+yFPQe5bK^|AJ{`GcN;G?Ln{7$(}CBkD9O^&;P3 zVDCfCp9JbopVgiHm_lZc2IRvF6zNZniyx|W3q=iv$4c_gFk$e~oR}!QW{ZXNl+L-Y z`P2~KR29`<-KT=VLDp9TnQIgDq9gX(4Gwtz_w@USiG>K*PR)*=@~<8CQK+F4AhhLz zM_cZX39{*GJI*lNo5p_G+g+O?(X)&&pONefM&h@d5wxeg_%*)=RF{6ouKd_@MQ zUJ1F*%Y#5cNFq-gl5Q_l%K5BOTwDe)R$Ft;FAEbKM|@NutVWJVRB;l-l)Y*M6k2?e zcu_Lp7Qhy#Dd27T6vp;v&u~2BlPpvkqnG|poffNL9r|;pr~k#gFp5-N49QvIp5Qb| zd*T7UkbMzOoCLnk{52rb$5yhgCou0T_50@ueHmBSX5^?NF|8{VSYLC$5^7(HPLQj8 z%+WDIfy>R&(r+c&JlV1Fgwe)PuMZq`ju~lbcmg=^y-9vqjMrSoLLM<;3#rLV2Rh|& zy;7ZIn<4OSQ{(l^g`hEUJJ^Gk2e$ds{ls&7X%7HBhH^!wFqc|?^$fa-7Uw*bq)7Ok zR7BID=nXb1`YRicOi+XyAwN&<7;+%h$$G^>F%48+q+Si2f};Syw~^iG1B9~wfZ>rv zA(Yqa-8QVPZE9K5=eD7*e-Ft3`@E3bs0q>r- zr5D*Qdm?<=h{to6^eNlUR>laaxy&3f#m7RkPvlTz=hp_I2jO;24uEUdF4XpY4 zhWuHO;J-AqsI*5)Qiwa--r_p2vC@ZmUhFB|krMv&>&o%NZm#GUZY2Q!Jsw$0)V40Z z!yJ5V#(nl7uvNUHxsl!K+c%Oq2FJ>c_*kd6f>`#+t&zznSLgBz=h`TdnjGsGGB=OLvbabbs0J528%U0GQJ$5ljo};DpS&n;NlkIxiL!-2LrF0vs zF71yVR4%lpHu!8~BB-xG_Rrp*H6rv(PG%9ypx?zy!td6}GT*gfY)jU(I-}oE7-({x z7WmBrJB|?kWc?@_gEkk~#}WXI3X^}mA9!f`cL_+*W2~U0oKT?-I*gu}zxDXo-iahf zAn2?pbisx&TxjQ&)S#XVuMX`%stP6YPKS&@mE?4K-ordp6*S04MTK={9a|9Kkpk)l zh)Q_ES_TnVUfo^fnjDdp9mmhiaI@73+Fi3Y7A$yB&VNvy@f0qpE{^&YO0|0lM3Ry z2*BJDf%{nxjMr`EJ<@XZ7lu^>LUWmejM1cw;6l;CNL9fI&(CqK%~ev|Ka8xeT>0o4 zSQK&t0?Y?g5<33&6XI*$>Bu|;QWWJJ;FSCjp(bC6H(MAK`=S9cw5a19^c7RkXrl>i zG7^LNN&u`#{xv$`l_lui4mcRuxm)xIT(6c?p3F(Y0Oz>}`v- zFoWyL5yQyI|pB^6%!PJQC^ zP4eG1%$#xe47r{4@EJk+WZtu@77j4ZWMXQhV;+^l1RKnw_|c>5$d4a_7xg8`xE9w2 zutBu7+lBCxyMST6-RMZMv>XG(S9cgEI@#1kjS#YFhY-5$1vhv8?Udb9#n_#wmbxAG zu4!hp)#RD;OfXuA&7hvORwaR4>we~eM;f2w%&U`%k%p)2zpHV*-_S5a+7~HTe|ri6Kz4rno!t^nH(MhIJVEc{(~2yipOd6q0E8TX(!fKjP<& zT>$6(d8LxUQ+4<0I&*v- zGNZb=8~s=F*+tk|Yly~XGae%t+rzEbngq@o$nrm7l)pIX_2nqpd$K+AK%cb$X0f;S zK^$H`t}a52Bi#rkti_iOc9FpsF~PPD&!&>kSQU(iZWK1iZKY%Y;jV$|I7$-wK&T}& zK6qOCT*OX&Spl!RGS{(d>!*O*g3{ss*gn-b0{U-^4+s`3)r^oY)XC9cN4copX#}1Ctwj%A z%YB@f`n>A1_b^0lUq&gubNn>ur_4G$Ab~?Mtjaw1!(mStq;GGTYM|R(oQ}{V?H=Mh zAna4)iPGIGg_le3;S=NHy_aC4>l!)lEXBdbKCPX*^;~D%VI-=$eUkwL2XWn5qs=6U zr@wyZ4AuQV8BI`SC0wc3S41WW(6G}y4$2mvmMNmi2F@@$F;e`UbmDl>4Ku;SHm&%q zniPK#vAO499ATYAxTH=JVfL_}$b3GK-`u<1AWfXrkB6o~fY6O^4c<60t7#Qs%wwiz zxcQ7!F+y!V4Yt(pU8l4#$LqpgL9%hxnm>nIa~c$^PGEdJKHP?i(vVK~2b5&*Q(-8u zBP(`7PF5rMqwK|XCoAK^1?dHSB}1g*hSL+xAg;i#c`W#|(+6v1D@2`jsWuivwjrBjqjZH>k3jji7LfjRnlZPL4-ep111@ z2XebsDqJwc_zv9f(v9@XLc7o-%7M%^&p_d>KEO1@?w@Yp0V&5YAqdIS$AGt&dJ%#r zr@$-OWm#`*O&wx=g(8{fW@@G@_j+z4kSM{^gKXyt)exih@ee%FNjNr+ckyw&CMdU8 z`)Fq-BJG4DvBCsJvGqN}6eEe~XL#o1fEUP`6Og^Rb=_eI?y&|!QXU=71w1^}EiA(upo}fOvnt!+4)?bF2G#Gcg-SfyQ_*Ya5JQR z)$Z#|c)%ekPz7+q9MNi9adMGYtOQpxPyEgG<>%l+p4q0@g$eVTHHWLqX^uL2W=M6z?&}NfzHsT3;w3Z~O8(M}p=^fzyY!=SUS9eA#TLHaFU# zGeSrP)lA#0>(kzig3!}VIC44`)mJ2MS^eR3TZNrj|A`Uzl4%`K+MB7%?)YO_!{TSI#u}uILVC@%V)0DP17pf zA?F$HQ|V^BH>}rvH>=@NhPcAwbT|}K5zY(PwbGeTrsUx&=I5*1=*upcAc%|+q+KwToP($BieJ-OU`^U^1 zuY%RFnQF?mSX3yU5N#eav|*yA*b$7nxw~y3zp-DbeePr;dr7TN_y8t?DbjKW<4Gfd zR#vXDMW4PwstjvgAn4nDb4ZcC^UxTRtoMJHsCg9KlEsOn2?V#QZl2$*hVsoON;)pG#NGzDWQynDV z>Iy1!dV2PJP@FU@DcH_}He!U}p1=m>EfO%9bm?ow z^y(E2Yjnyr+)sUp>Ver_$>Fy z!c2!kgI)qCwC;>D37TE9Szo1-u<^}6x~oUM+S)*>=KBzhkV-VeaHy?Wfjb1&l_qU4 za$J*(==+~$)81xGM)2CNBT+Ol?6(7)Q6ljdTNAK_u8pTN+i$#B)%B(dB6iMQV^tb< zPyfaPzB@n)%J-Ix&-!|rA8Lt5CpG&9ot~vXHB|x89)i`*u(^Dld0Im@} zy7Dtbwq)83M7=>%AA2F*=aiM*HFJ1EZ5#77X5YlS5*1hxYz^`Y*)YWc$ zI|WJV3Grj-=KiGku~x`)ze#DmOL|J8nVF^@A(&#g1fExqL_SkzNbg%xKI?mg4_V=n zfu|3i7KprV<=^O$C_50~X(a@P#l_YUaVdVKgLn6G+0+9*?An>|V6)-6hi0vTN;|Tk z1b#AW3NTZOm?a4PCKh8Fo{doV4_8olfmufos7v*c2Hl}rLg2wQTx-u1zxbX(|D_na zBf?|+O>~dSFM>Gx3D4bMhW5fV@}TwGiDJ(6c(6dGnPphGQKjig7(g5G+5-Q&eh0In z;U)fo8J>{c?2#!(@(Nz>06j~9b&nf9X`gRZ4g>Q>U1aD0n9J<&mn_xTwSqY&9^*fD zY}!u*G9Yqiy4lXsv*i47zJTLQ7q&ZPAQNmBpG~onS=9~2$)mSEV%((r2^$)#XrBS* zRA5CETXB6uU6(k{bee4%(Yw&i5qaaCWA6?$%CLxrdRI#-VOjs8NnW#LA-+%Rmr*zJ2(#V^pU ze=H?QPv758YYnQ8Rtsz(Uw;dPxnYM^aalnI{%CPemUheYqBQ1yztTy2Z|T!>ES4UE zNWm7;YM!U0%gdMth&h5u#*yV<2}*aWBhLdtj|zp9OIi?y3u$jXvmVqe#af{8sP?)Y zBn@<*_1N83jKA3EjU^-zj?}O^lc?ama6}1T1dif4)SS1Z%$-91%PakMf@jfPMZhrX zDt-)^AD7QD>DJxGIK`loCzxvMnUZ#E9v-4p4wr$3t#+97DH$&-bbh>*Hi%Hr`V;M- zQd&jVJ$m}9@9Mua#H}-amE_#IQNLa&P*nGaW?p)@%0SKe>NU@&dGMv2(2ks7fZ*n` z=Nap;;60>Yo`huLg6UnP``(FZs@eh}HSvYIeALIVe`uOFu5=#peE32!KDJV|P9Yu80{V`;3-l#DHuFckc zOK)W@dG&OaZ_bF+{oZa5cPi+Tc8dCh0Q9Wz1ZD9MI z#I(CZq%PF@^$T{ChTtWt$MsQQWIa|0derrJ3&O=87Cl`M$oQE&PxLfezn6`KI9XE? z2YgYLf940@_@zLhN2{yHK>SF1r?+iG88ugz@5Ilw{-D-rV1YH@zS^Z`#aw5-4B4nl zx@KL~0KTi~!zN_@eJOjw`f0MwS6_2jgwvnx8t%ATZPTx6&l{ghl;nx*-p#-8(mGrc zQGAx<&26}P>c^3yub6HfS$;R3cqU})N2lSQdd{j)Y)8nf36cC3H=CnV! zGY{TSBC<3?!4xWK4sIgHGp9|iJE*&3dqeXurEYuc|LRejRjQ=dz0i{!6mN zFf!@Dn=)sKl(T10W0?iaf4GwZ}@cg%MCAO7BjZ^Y}}?& zKxb%x8L}0wee3yz-s}s&SkBAq00t^(cgBHCsM~tala}{8$m}BvzHgCC-qyQ)Zjsnf z&OI#Guqy&HI#5?PSx75f?h?#VkDTd$x)HfQr!y~`Fe8-KuHTs+oAIU0_B_PD!C$$k z;RHM$t(INA^#~}a6MiW4xx)|CVgz})Li*Pb47(&L;zK!fO&tnpPCo;_uc8hVQ)>4e z+1r{sqaSW-?&zi?6u8`A;ni8R1JI)%=Z-nsN5s3>ObV2&7rFOscAacu>XCX+2cGNh z7VQL}SnY@PR=u|sy798Hk99#!$QWR3uwPqA)MwmMWc8jpV_y~aifl;z87!p?^Q3gu z1|6XiyPn=wwcu!C%k$ik`~?)fo|8kxpW_1wX5@Jms~F6hb&SJ(XLSYFCYlvtb7}rU z=s$vPC6%%Q@7&Wf+h!4}Q)ZgfjrAb_shR%tV*LZY9G7GdO?Q?0{WLA1c%o^{{AWRH z*8ABhLtGL4~hcc6GR&)Px&C?@nBJVj$6nmvr_*$kXko1=ZB4Gtp3 zK>B^kp4K8Of(_tKs`D99Bu;fHFs;S9%jr|lJ>nk$R_ba-M6X$=+`}mHaibU|@hm=P zu5V?Du;sloJRKk(pY$OpwC2`Z+NH7xaF_eO&2RM;GG7mJT&DP^TGjez0oq8?-acux z)QHeGOcWBR{y#>k-D`Z0B0s(9*j}`Q%D0(6qG}CZ4!yVgK6ZepL?k#%KVQANS*SCsLsD zRsOV4!rED^<0jXv_yttio%E4PoK_H&q)hzyT7u0zlE#F{1K??*KeTbX!@DW)F(n%b z)0~+h6L3#WKRS5!(_JBMoI^q{CGe|iP+6bPFPjO^qoQGBj?S}bMmaC^ft$;jeZ`lK z@zvl?RNh*56!~sn3*EJ@IwAAd6}F>ZYIEs~+nL9vn+?ab8}7CzWJ@h=!ZfIU1Pi#tXc$jX)=iwQ* zMz6>>@KImd2ge^K2~0(6fqh57R0cMr8sYQk9@KKG&K8trtXx} zR0U_c2nmJ=Q_EC!h{maPlF6j)G~GHf)2<184C?6(c+YCKnu)#+PnqGZhmQ!H!GF7Z zce*~T05CIvXj8^D>_zVm_W&()EBSUaX#FD!l$x+^fwAMoN(*h>YKJl+vd^b`x04=L8c^Jr7GH9bn)mn^%#(P8wW#J3^FVml z;Xjz+DuI^ne}WDckS?yDibTEo9%3bK!6HTO$wKHAq;Tz#_#kv+hO<7xo+d;de#D}C zC2yiUsU?%KSJCHV2D*EE%}YS}!pA)IgB_BxJUt%`4Zz!@Kc_)RP1~X4fKg{VioM-}{kWPRw_kum3e3 z_>z4J1&6TyUtfz0AGVPlhgU;5%&7ab*3=GtNnxsW&mmN5VY{uGaYA-{;SwcSU$3zK z+?;0u!(UtL8Zs`P>=zgaX~gwX>UCJq zy%#b4WB+zyd~SgjtGuq~k5Q3nCz}iC5rHF_hYQue!UMtYNiCw5#Zy2H^&s~VJ1JVK zUF=lJkGuMO5+UU4HEK%l{vwV5!s~>7UA2^NE}B~0h?)=U4$s;x6uo;QqMwigIzNf) zv>COAy0j>k0K#;?=c7mZ@ygj*Nx>BBHX4+wp^{!m2XcZ*{j#Fpzf>M+XRTw<|rw<(jS}FlEp` zu74o0m{V%aY|_5uL*2js2~$VROlyjHiCD6}W~;tWD45ka{fb}5FEql`dtR@J1I~?< z-3z8*1nr^gjA^u#(}IN%n8MSGl(%jTrlhczCE!e#a082d8_&|B35vf+)wqcbp;RSM z@XAAL{s%ylk&VL+T=-snMHH z{}GK-*6(k`JsP2HbXyuk4q{SI00C2bdY>!iShD`O8L*eCN*K~#39qY%M6%CFq4T}SdKL3u)w zyJNGS;ZD5m9&%T&^d~KQJ_x|w(#clm34BM)S>L&19?@?hKUjAOfW=A#4EHaCW_I7@ z@W(05B=!&w@gt)gR(`*k5b~n$Ec{Ny-BUaIvkXw6sK%cy6B8Y;t6pC}Z{WUNz2hU= z^-8uWeLmbN-xK^20AhXPNBrYs?U_)ABkJ|>y#3?(^#(0+@&&ABov*V#Pk@yrZ?xh( z`rP#|cKyT>(*euqy+X(z3G2$Nem2fn{O5H5q8@pjnu$~6`HZPv+T0spZ+`aW%Xs zISg;NWp|C~Y#_u3ABZ@ujf2`!M#pc;MOEK)7|=7g-br<(H)<-;!cpe8$Fiu=>j+_H8FY=Y5WrB(1XS1a+UYaBM%_t_M z$YShS4H-YTxHZpf1)glfs+plR54%3u*Y2Z{_Fij;F&!5sh(=z2`88{LuwEfLdWH}T z$`#8T5+01|EhtMRjz{Fp_*_}&tPc)ip=u(!-w7R=&&sw~8_VM-va;3*7BSa3E@Gl|wwbuq)5O1P z*mXDLQeCCZ)%}D~2|sg->Z>BsP}kb%A#UOdi&0jZ=mHC0zl%>@ThL}?&o6h1=6e+e zo?cANc{!)xTKV^dk+)C%IQHTbFWOXVKgGzxwy?}kaMND*at5nCZkKtuVR*0{>pFX= z;)`5s8*QkBe$Ui=T|6YmkzD$I3(w&>?0Hq04^FO>ox&{CBbaIBBf$C4WbpdANGmcb4<8$-qn_`OFZ3C z+}I3%xOEbo&@$F3ICHDZ*&HCn>t3h%T={33PrxH?wqhoSb}0|r#hL64IX-m-P-^vL5TJ#7JM$6W_NS*W zKFV$RmE|P9KC6Wg*SX&HEt&n0b%L6^ULz7-_KqPrw|?a;zYsWxXTrF!rk?N!L&qei z0i1FlaYiP!uX`)@U80P(lrj{KR`fj2`I|g=6+9=cllVG(;#{zB-I7P)FSv25wmdIO zh@OqgS!gA8ldsFyUJnf*h-JD?9=|4Q%s%dt$t^;MdS@tU07q23q8ED^>o(V2(E#Qo zQ4*LP;97eA;_8$fv3aK$NV+CH`AY8-$|%h(=heW0QLZz>_D_-zbG^IajslGK%sET1 zS+1=o0YjBx!#W>m7wB;f&f_Nq9Rank>iohC-GZRAI#fgl-hP+W#sU^F`l>w;r-g?W zzuIYtMdE_eY_IRM878yhE_rj4H3em1iU7{AU0cr9YihjQsBGv3ARwD~#zCTwl4#E3=Ksn>rge5Q>!+(Y1d8-6!PQxPcR?W`o91 zqAfNtp0AUBw-2g@4MRc*!53PTY`w0vh-MhSiWEU^w6B&o-yO{eNzRU^WTrenHNisd3RzW!D9S@aULyjl zJ;@oKWE`4WNt16g^4i@b^oIM;VGqJX?Qdu@rw-g68VyQk<{|LN;k_c?e8p2@F!UJX z0%`Fwn5hJ|vVNEDdS)JMcFvHl8Gd-Xt}2_+xm;)wvqRj@GF&G-(zVnpU4nC+7Qnz< zR)aFow5e00ABQ(0a-^A$g62m}mXa>9I`lj5b}(`ngKz zHl|Tai3wF)Y!EQrC!<1ND)1pLnz$n1gtxZh+_%jO5th|quP@k7F4Mw>=C-^jF6tuP zLKLwu<&E-?i*2a6&0-uQrja^7=6g&L`5NMo@v&DZb+7f=X!Is8wLP*vScsjje-mau z>t`6Q>5Mm@+3l}uCv6=MJU$o5t855oujqI2PgNP7;9Hb4TyzOM<#M=)7c#=L!j(RR zr=8sPq^pv3v1Ee ze_EuVapzwem;oI+b1F{E^-(y>g_PgQE1y}|d#oEWA?tJk<)kDL-mp$p&Je6C%8ve zPH#+XQ0%p`?|y1KYZHaUs_m1|B~zrkpAt#X+U2W-x;}_HqI@r6{lyG~E>8NaVUsE_ z--&E!qbp}Sh5ZP4(34XTn9sEz(wz+pzFTJ}#hf7cXQz3xE;R50edTHdKck_Tc`FUW z(n#Qzxp^srQoZqLW-AcpPoI}{?&f2?=##3%G7rI)aBE{$+lLd>2E1QPCPwcag1s`7 z`lNLgqP&+oJ9p=D)%FQ_^pN?=Ss~lX(bFz6ilExXqRLA(QO3I%B&h=2Es;) zN;R||tHpEB&yN!Txroc-%qzw+>o#ukNo^e6yAICd))@`LTJSculj>pp zbmK!QQ;5-1G8ZwS$1R+F<>m^F0C+P;cu6QHE_N$Rfhl4i2=HzFu@vrH2!i>C{zo$@ z5nQg||2Rn4g{4OMy{>w6gMp5apHQqofK6*_9yhGl)Mq*8-t`H1QKKsmoKZ-xwCOED zX_Ylgdm%7zJ}RYR`0N({MZ>^evScdVsSq9D;_x}25;J54z!|l?Wg{JV(eh`e0dwP! z)A%{l@=1IA`VuczJD?Eeb zwBI~@FFS_x!=&)sMvfz4vUxz|3 z>A4)Lt~+4#Zgli8&Q1s}q(BcT5zszSlVWcZ!P6^3mg6KbE5qDBvp_LlgK(mE zfS$;6wV$4E1v=4<_e4R-hEU`#Dm@qjJ#{rKxniTJ@Pm#{%TI5I=yq6?nnggyx8lze zNpw6shHNWqC6Zi5tYI)~)wCNdm_jaPca;cLzay~`UZRI*^!e)ne#ZqG)PtCv`Szgd zA6t1}ok_IP^%3$c@kSToN^2WPu_sDFJWfCKS5~vKa}!wJImd-VVRUz?XgqnN-PPyW zJtjc3??{S9Z^%Zf%{C8j_k5`>(W~^?51dY!eAqT5V&md^OZk`I{`&9#_P4+PUGs_= zECUgvEe=%2vMa;TKHyKNYOLjlxU%&dqAQYc19~E>W|`Fp60JFqnpdP0mN%8k5I0Kv zc3cEVU;t2z^zJNMojuPz6m`;ywm7jgpUUvHjmW?0Bt34|kEO4*jtT1dRY{TEI_%#; z*)_l$?zRDLErdJQq6AUDet|>c@`!9kmmqWMbaa=D9!&Fz77Ed$NlvOEfpe!e1rI^X zK6GZC-Ss$hEGwHEG%=Bdrfs)fmM<@hWjAUw3eKG$PB>X*12?g7P9b5wD2l7sHqVLiVFL%JYSClkCl;b zMDVK4owNF%uiKcZu>ekWY(3}2!FJd}malY%i=g0qQ( zI#dE^X&cg+tKB0F91Afpp_&Z2J#$8d(tSlopIGJ(1{Xe|=E34f+mRx3fQv+-XYn=c zR!;~#Qxjq!7NKAinv+jfRnKXkaufqCMTBd}P-;J8NwF{tFyE#=8GYY7RTrLM1Ua|D zcJ8sr&hr?U#m~=cUW8k@En^uOD28A$d0G7qU9iK*W?TY}Q!VNJ{9qJ#TKkfS`IN^} zNHesjMN&W_jC;A4s8d4ZU^)mIe`7YX4s=fF=9-()siS=(ZMMn=Yzv28z%W`yXPBL* zbniGGvsjn1p0y6w(V~l|eAmQh9=&5&IOW6vV>vvpHLN7(3Q?c+Oh!)PWK zkj?-G-J>hPoGl4)9(DzMOBp@ zdj8s{4k1bkp5a99JUrW@ci5~D7L5$EIgn_zye>!G<9h~yUabWIb;mf8c`D!11}Kyx zauY&ClTN_;STL;BXUBZp$7$r#bC%WAW^!PvG4v&YTN+e?SD|q};%J~;KOi#9Oi{qD zGklbE7Z~%_7aRJR`CexgeWwT^B)H3AhpvG)*r4a)u@VhI^~;zK9BSaBoOj)pW!q9L zWDuI*r_3R&0a2J4HWlk&=5KQX8`fKC=y5KJ#@Zl=D@o<`#Nsyf3V^j}*W)(f*=h-b ztKHPmesQS~RghKazPpnHJ_lR~2)@`Mge*mQpkz%j*A_u=)+}nsw+O$=M?(O^ddyU5 z*RP)hdEs=|=n0>J_0m~+kA=j;qj4oyjgVN@g1$NZGgSosl29<%e_rae({DYvj`D|X ztf)aQPZ&ztH3c?8el~Pb)5H}2<6=|H5Hr^TZ7C*D+48b_s;j^6kvaH4A0-crc>(?F ziR(f#zGigWlqH9!LIX^g;=u(hPYaz&xEZa~!zak-GCJrcb8}(m%Jy(z0(;{$uG%Yk zX1`d_X=pY$Mg%Wpl-IIKt+6Lo9H=qk{P}!cv?6&kzeg}S0m~eI-D_umthHTx2&1oe zgfQZ1tZJ}B1s6TTIYO}XpoD4_Rpvg45Tx&B*}WNF(vN|0lpy-d($2>zI>siJbcZOf zB8PJe(*uwATz-`Kq)2Gj8tj)C_kiQeW9~>WIwk(HoZs}BbV{x0y_Yv58urOVV@T;f z6+HPx;|p7gC&4ToZm|}2Luz;}$QjNB`J=n}sPn^uc+H9mLpTpo8_7vVyx@M${c`^Z z#fm4fvlr|KwP$W{eW@--*VUaxD!3;n52d7L(OmWJ#%7ipF(<4$)o%eNs=Z2|FU=J{ zX-cq^v{`Q^vMP{9Fvj9-gQ_E_^&j(h5pcI-NsqLDXVp%`%dCUlkR z+r7M#7U6A^V>!3uNU2BYX)on9&@HU3WmXTgC;26EV zuK@0}tc9T;zAD2rR!Z{#?56=2+DPjtM&&V8DrPxnOcS>D#qK*OA6q<_9v6}{<}l4{ z#k+#x_BB$`x&BZ}_hpgD$t<<$bP7~^pZygEEXPu@UI!RM!weE= z4qV1Lz{M7Pf%isKGTeeV<9Q0{n$S+5un9E3{k)tIt3Pa62M*#C0%0bX&C+8X?sE`Ldg4;N<0bZk#ZEp$V6bJ_0s+Yt8*kjZbl+)9Q+8c%O~Ji zeUbGQA$I)OsAG(3lX1Dxse@6 z*r&e?6hibNHNp##467^5y(@_=9CeytKWzK)I-vBE+DCi~Vw6>hL7m-J2%wAe)`(X( z4;5*VF37a|(-F9%2C-Evg9n}XBh;-|Qhag9#ih~&mPE^d9BOP2<&B#LbDOryLsA%R zBgc*;u&P%ciV080Q6PzYA)e+1%i8zwmaR3kfKrKgh7>VWm_pwkK!nvW(CqbS@4(Nm z&qd&3J^pXcyN60{GOoxRB?3MW)pZ;CVLoG7<@upEA(uP`Xi#lVV{WK9O`wFX-87%z z@KlL`b7Hv}=kUbzl9W8hj)iY;BlBRG?s z=VLG)KTJx*=fQkiZDDB9BBP_Sa9TfMMk)Hbq9+wbv+1&cNyEqjj_O>ff|(ePSHK;z zQw}w20KJcZ{60+C^%r}Y;>s&_^ZdGGXORQDd56tun$c8rZCA|n(p}-EGDWo9a={N+ znZ!)WJ?n=GL~vLe@O}gmV{DJ$+jjS}3E2EHn7o%xm-HSB( zDJ>d0l}6D4>^M9M?uRu_fM0hH>qE@VVkW^TXlbl~Mw{TB^!i4%H{jOt59JqRGmN8e zK_giggRO5%X*G0Va*A@+kQDWD3<+2PRqqgfTTfN>-kxk9+q~nG3B+SXF-CZ`4uDly zBZ}emLXd?kPT<|#T9>ppTOuG(q^$2IA-7&#cxR-E-*e*8ZL&B1T=lmedGTDES(ebM z%yV>vRl>S}86(-*zaHBm4OlHfbuLJx{0x9d31Qw4-MdpZI#lUYz|8!nco;H|Cr(#) zba529tW5(@TuM^=nG5nQu`eY6SDKjv=&vuz{2m4puwpbJouR{}BFd|lq9J{3#!??( z39P>aRl=t|y5&xIDndae-BXZ$d2BWYjMD;k1!cn>yC=ny@VC?)=sH5hNx%2 z3Y6&e;MuJ@A{4P?`d6?r6OR?qVmW!;(Qnf##q>jCG=!JarMSd|ZT*`!O#;Y~K+O&$ z(rMwqH{un|n@hB0c=j0;L6A-9GU*KSA+_!UZj&vPv!&|*K|sF0A~qC{98$MwWkXZf z)7%z7QGGizFZbTS4z~nI5uKdZa(0Owfd|T?(LbzR1eq)&ni?uwmnIUNnig!VBME@Q zr@Bp?rnO+*bI;r2Jpx+IG3dt< zWB~}o`J;mQb zc&_+ypowR)P%F_6Q;LmHp*6tJ9;yzBjEFo!Z2)`3ujI(JQzSwT>T!|uy2UlKSx)6# z&&bSJP3sIFS*}SD z;qdV~|7PxppW zmV6K$B+L-1wVCgLZ1nINZ_GQV7<=>`HPc8Oz7JD_!-w3^_%j`5A`Pq7QG`sB{+Wmr zIn06!O5<}5nd|tIo`1Zrl$|+enS0wA9&;tN<+i;)U-e=CAZivRT@a0jt$IGk^4z3V zE-;c0WtM3$uo{vKkzKA zFta5q$b1hOj3%IEeK&nl@vLrocEu(L(c6;uCZ*Dl#$N@%S zk1r84<}m}}_0=^ew=xoZ79*)PwBu#+tY15pIBaCaya>qzQa_zK6@pJR_nD=+(vb{$ z{b9uT+%ipCmGeM1e?&roHq?gN7}6BxO@)~XmSS0jK*kTfKULZsEc zLjT9CbchEcTAXlbJw0G+U*GIF{yU(g%csDVj}p|hPV5~xfNZ@EZ$@HA+Vn8Rv7IwS z+ruKEj7(E-gLG{qDM%Ydv62zXc5pp0->kbI^AX274o zC9N!gUcbD9;2sxyf>O&}iRtTyodoAj>6To?#5WTK#M=^)SxdO1m|4k?(rx3yidqe~ zW0(xn5IZz~;1e8gzQgi{`v#$yI1Ff`9odNPI=hjlNjWUUh7=cK&fap+-p~^FL5`}v znUCc)wV-Uj>?KjS{3?&1LJPcTCr0PiZZ3%FrpPk|mwSW&Z@K_65Ty@kD!|w~Tk#P1 z?YecQKHBkVN%yyhtkpv-QTTYk#+afB%&@x@58m6lC_GHu&j?)^ z6;(Ze|9Tcsx0)Xk8KB#8;24jDge(-4 zT~|yHaAQs_8SSWSwDuB4ISQ6rD$egPh!_m&Q9Jq zEQl*rL|ksI#fOExvxJ1rA0woP^cqSR9o)6TS{;cwi~K3+pHkHEf|Q>LoVxN{BAoK)y=|BPtM$2A=+x-- z8C6IF-(WikR?m~%Zi3x?tFWFg^KsP{57Q%Z`VuK;vXL|>glT6u6aq{3fOJV+E90m9 z)}U_2-P>p5d(dTvcAX7GSRKC~?!p6h&EL1>3e>BpO|3V6KZhMNYgBpal?~=F3ECkE zYmWuh8NIsg{=nNTN~ZC$GrySR#s|K1mntciC3Q3iUhfYpTZ`hf)7pTUHpD(b(;~}+ z86{t-hzeNA(U+awC0&noMM_?A(P!F$hKOG^n)*c4S&h3F3y+@CorB?ApEv|v8g&EU zyyP$&oM>u4sQ;Jv}n+%iv*1bi-D_pe!HTw6WOCJM2}OEM#CsP$slb?qbtFj9t!C z(;Tn`b7qM}6UY9ov z*xEErK_lM8W3)95IZW*7v6as8qDsJ=`*%@l~+*;rywnVNK58_uO)y>O#l9M+zie zOP%$gvH;X(+q0Q(Cxs8eIBR^kPpKqoICdgx(-Q+N=EFJzdfJGSTRH9YTiTsRdh+ykFW(T=6sL0c53+h*G+Rx-9b!2x=QG!3IyA#j>wvUq zCfUCb@bGN~B*tk%mCYzNzeB9uj!~hsly-8!4XV3HK*w=B9_~I3VPJpTjj-~$Mx#I( zRcqo?!<-mzAMV>Bceb$3Gqts&Zox~)+d7MMz(j+DjvmPr#s_^s+eHGw4>$bq- zNlzZpoKkb*PN&DXMKrgC7vxb@V+UP~@Q*|XQQ+-r!!wc=a+Yq`VN}K}oo+B_Iv7bl zbdZ*Qr$)d#(Z;p2B?%uBJzGDA<(nzuB~*wcBaMh~wFnI8>f36JfNHJ8GV`fRs2W%U z#o5wZ*sl#W*8;Y}dO8rjyt6@aNk9iu$60dH(JAI5EFcME8&1MP_ud?g;UseQfKyHb zDrPn|?1~!5VXXkge3i)?Z7jVg+S;if!N~12vkxg?l@}~lr7Ezw?YVajsyrJN%x7`B zzrB5E!}7s#kK_5U;r;yC1{93-)p3K3biQ*1Ov3#QEqZNhp8zL1Z)1N~>{-W|%6)y` zIGqRX0fR{MFWA1F$~3m-qbvfrjLG0-DM|1%!M_CVqL&3`!j`bYPSk% zXnrW&<-oHe4CVmRuZwmPwZ8QVW)gdNehsJ6=)Yu+&QqYJEM#Z~WM652Ge8XF4Q}PM|W~JzO-e)rQrqZAC4_Q#^gDMh$;q z+>08ot+7>)@Hj**=|l z$dFPk17QUPlKhgCml{TN>%qXT9$>)2nBEFVZR0RmD3RpU9}rKp5M!lc@hKF6dI_8jO4EzEo!?Xn~iYghtak>&Sp0> z-ynUV?EajtNl@6z_V_$o!Sid99}br(jXq;ND1@~`5Dhr49G0Mn;(v$H@0EQQFKM$|~mTN#W<5FjsPS7o} zV&?oJ{k%s;p%30u*z#r|=tc$4Tp3Dz7F<-@WNxx*P1FKu#Y*J7TxV@T%QQ=gWXHe+ zh!y2ejnOoG=S5-u+zF zKuBnUI-ptL{q^r*c5J`}xk74x7o1a^sz$NmfYBhLJ2l>ABG7j$hlR!jSy~aN!3{_? z9YC)B6{tXNvTscp4>4Dq4+lndMYh%sqJuV)o6+XJyFGHCrnnFGp^^_oUj!m#%5|iX z5w|V^^#$}Hbt(r%oB3^=)Y8`o)f>M=amQoP1Km@fV*`No&^gj{)a1}u8P_dkf*bW4 zTh61?|DZDPnjjE@tM5@+5;}M03E3d-D)ALt;M^3uCbJ0_rBF`;DFtq}1x z{z8w_?u|tE8T-=ArsCY;ecC9~5>r5HINMV|<1JN>4G}HO6?~qcp}}br_yGc6^~y#oE7Dd!0=0Pr)DnZw6wVhdLCT6B3o%( z=mu&P98pp$PW0pTnQq9-J|bXLq-T=xXIQ{mQ`ar=@;t3nOdRnpd1-MIzbz=AV9lCBBx^g;PO3wEu#A0b~%ORqEHaBYK_E8I^Snu5&gYNq{Z!O2PCQ4F@(S1T5|;`#buo{=Y& z-U$kH54EMx5=B4|@RW*SJ5y%4f2F4|s#xW5)2P@< zi;+npuh8S!3!fp{B5wyHfj} zD(bOUMQ8=2CIfQNYCB*$*EF@5r+PIJ4XRr+a1z1N6l#Zf4B5gL5H+V>{J=3)gXaK_ z`C)_zOuF%wLxAVGOvY{Nu2I7uWj%aGNW~l{u>RsM1{zKWcSFwEeiAcHeB8Id*etyc z?+^`3yB&xUnt_n#nx-_jV!om1*BChxg9f+V=^|MGBZL{QbdBWIS+MD$>=b5hP=LCi z;6N9sWiXFP()SrX^@O)!FXgsBav_FuhF+3DIN?9y@}{CJ`UtIzsNLm_NjJr|bR0m3 zVKw}|!_xM$h*3&P240vc?r#g#NJ!&+;lb7 zk2#+!6=8|%c6hi#w?=t)Yr_Y2BuXteBSHhG<*|>HSHu$Ix~vJbuV{j+E#0Z|G9rVH z_T8URb!KUkp%X!JEEC;8qUn0Rt~t*#d5e|bmuTVd=Z^~%l=U`9P>MBJ2D1{sB&=EP z!_GJ3%I+J)m`7?DeIAG&SOo(I9R&Sp9u&PNgnp)7Pf1iCs$pvxM};T{is<{>&5wfF zr{IW=p?Q}xCj0i0LKV6dZ0IA5KwrmSubEwG&@^9laZcU<>NStfV4@vI zitWvFGQ}qIa8<^B&Znu8F?{LVrX9$&3sXl%dAkn=Udv}s*r!{`2N$-(e&1Wv2r+CO zk2Al%M=|#9W=3o#^k5qA+JP2l$wdJS+#R}55{iqw=siD{*a|SU(Z}<{E@>e#CGJMI z!_cV~=j7k0mc-iBj;~Pn(%THDaw*1yDS=b>xh|UmKzLK7xkSMFb!N{~oxq`m4inDD zY;Ean7C=l`U~4r22DAyON5DQIi&JjgL;e4GF3P;nP3G}iQ)J0FW} zgHNcH1rP*%@M`AGYM^=22Z~1cLaKx+2@F(nvizJOH)RuI9C6451=XFGCUVE%Kh;hV zY_~B;plq|Hf=-sTk?7Z5d4#nyOTbWaK3&&T<9O-Xo5S&I5#ys}T^clsB9!IdV2t)K|9PGw?)=pa3w1@4g9s1ge9axMU7W$#Noe-iGRN`vsw_gc-VwRv& zkonWq?3D{wL$e3^8;RZp_n#$vJM#~$i$t`y06$oIm0_!=Hu!jz^jzPnq#6Xsku7sJ zwIlQeg3UV&CGKh$5o!R-U4Q~|#F#IXEg)zl&|pG-pO0Z{-`YXF&<)^EI!X*7JRMBOD^FT`YFdYPvOwC3NGRTL=I^l>LkCWwKr4tmwUfcixGt=CBxa-@2KPd?$SManb zB!)G>3>hLJaKp{f^NCNLJMRuIz7nPRgw9)*KM0n&b3$}X%R>fNZc5+;c)H2gkkwBz zIrgwZe)Alx+(bjqA~cxe9w`HV)I6WsotmGFz?%SIfVZ(&UfDJ}{hA*jOLzI!mefYTWAvQ4xsf_G6sk z<^9L+dWyJU8uS%Ct}_Ra*W*qjv-M#ec!miw`J}$2m7uFcdrf6O3ic9LM}|tG4v_Iq zWfWm~=|-8;-1Ve!5Kx;RUamNtg&C|t51&gJ z%Jrl%CZOtSL?+@tT?Q!eI-hht)5BU1_#zp$sl!NgCc2Rz*#tR9q44&?#97dX)2ygz z(K}_F3B4aG`C{s~_pqXqw`ABosA%A1Z)xa?c66GFGd8h;J!49VZ%M6Xqfnudx{^b1^47Vt2s60()8 zD1H~+=tI2H(!i+H2OY?D7*%V{?Cei2!+FQnvD&+5w3eSdBnF@%4cq6vlB%rLcZEZw zR^=s;4a8y2Y)H<{e|vI-*WP9MgNr;(T4+6B+a?O3x0mr7Rf;TcS9zoGq3+LGtPic; z#6g2tOq<`gHB*=;duj)O7#meJbFj{}4gEU@iM5Z-Mh={ApOy>{i}&tr&62%#GRK%L^9$5zWO<_Un>sykb%L5|pS$PTfnB&&b^D=Xul=wFIUO$p+h zOzV;VKF~xFg9Q)RBRv<805FnZ+n1R|=vDC^{7Q+KS?VFE&~3fk%G+FUYc{^V(W+U! zVN@WhgG9V2=b*DPxnCj9o4mE#9Es!2?At3e#a%amKJl*mv>HacQY9K))*M74a;N}G z!QWkYB1Me*rq%?u4@1uzGa8q`j7QSf2zy$1KW-ZIKsz{tK?@-j2T?EZei?vz9hshB zm7#g1gNs!Bp`%?DaS=?6HO)&9(N5Y8;kO(Oa&0!OwX8e$b-I zne$UG5!mCiE+=MTxAut4I|#G&CA={EGW2GEqF>1r5ZJ^(yz`zC!$`l(8;O54GXS~O z=6)qsh{H1`Zoee)q0Sd`*&T(JtSKB}$Str4Mg?cLt=EH;l__XUiBDxq;R@~A9xS`y z$8(3z+(*5f8e%U_6GALh_xseEf)FPP!73w>nmXUc(uEA->G+1~vJoLrsr8l$`CT{D z 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
-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

d%$ZQmC-IQAP3i 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 U0wPpz|NZ&%7q?T!TqO1g0FhWSRsaA1 literal 0 HcmV?d00001 From abdb337fd633967be7e431ce5dae5968d714f843 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 30 Jul 2024 15:43:40 +0200 Subject: [PATCH 11/26] Add openai tests --- meilisearch/tests/vector/mod.rs | 17 + meilisearch/tests/vector/openai.rs | 1761 ++++++++++++++++++++++++++++ meilisearch/tests/vector/rest.rs | 20 +- 3 files changed, 1780 insertions(+), 18 deletions(-) create mode 100644 meilisearch/tests/vector/openai.rs diff --git a/meilisearch/tests/vector/mod.rs b/meilisearch/tests/vector/mod.rs index 4a142f86a..9935c6330 100644 --- a/meilisearch/tests/vector/mod.rs +++ b/meilisearch/tests/vector/mod.rs @@ -1,3 +1,4 @@ +mod openai; mod rest; mod settings; @@ -7,6 +8,22 @@ use crate::common::index::Index; use crate::common::{GetAllDocumentsOptions, Server}; use crate::json; +async fn get_server_vector() -> Server { + let server = Server::new().await; + let (value, code) = server.set_features(json!({"vectorStore": true})).await; + snapshot!(code, @"200 OK"); + snapshot!(value, @r###" + { + "vectorStore": true, + "metrics": false, + "logsRoute": false, + "editDocumentsByFunction": false, + "containsFilter": false + } + "###); + server +} + #[actix_rt::test] async fn add_remove_user_provided() { let server = Server::new().await; diff --git a/meilisearch/tests/vector/openai.rs b/meilisearch/tests/vector/openai.rs new file mode 100644 index 000000000..744f239bc --- /dev/null +++ b/meilisearch/tests/vector/openai.rs @@ -0,0 +1,1761 @@ +use std::collections::BTreeMap; +use std::io::Write; +use std::sync::atomic::{AtomicU32, Ordering}; + +use meili_snap::{json_string, snapshot}; +use wiremock::matchers::{method, path}; +use wiremock::{Mock, MockServer, Request, ResponseTemplate}; + +use crate::common::{GetAllDocumentsOptions, Value}; +use crate::json; +use crate::vector::get_server_vector; + +#[derive(serde::Deserialize)] +struct OpenAiResponses(BTreeMap); + +#[derive(serde::Deserialize)] +struct OpenAiResponse { + large: Option>, + small: Option>, + ada: Option>, + large_512: Option>, +} + +impl OpenAiResponses { + fn get(&self, text: &str, model_dimensions: ModelDimensions) -> Option<&[f32]> { + let entry = self.0.get(text)?; + match model_dimensions { + ModelDimensions::Large => entry.large.as_deref(), + ModelDimensions::Small => entry.small.as_deref(), + ModelDimensions::Ada => entry.ada.as_deref(), + ModelDimensions::Large512 => entry.large_512.as_deref(), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ModelDimensions { + Large, + Small, + Ada, + Large512, +} + +impl ModelDimensions { + fn add_to_settings(&self, settings: &mut Value) { + settings["model"] = serde_json::json!(self.model()); + if let ModelDimensions::Large512 = self { + settings["dimensions"] = serde_json::json!(512); + } + } + + fn model(&self) -> &'static str { + match self { + ModelDimensions::Large | ModelDimensions::Large512 => "text-embedding-3-large", + ModelDimensions::Small => "text-embedding-3-small", + ModelDimensions::Ada => "text-embedding-ada-002", + } + } + + fn from_request(request: &serde_json::Value) -> Self { + let has_dimensions_512 = if let Some(dimensions) = request.get("dimensions") { + if dimensions != 512 { + panic!("unsupported dimensions values") + } + true + } else { + false + }; + let serde_json::Value::String(model) = &request["model"] else { + panic!("unsupported non string model") + }; + match (model.as_str(), has_dimensions_512) { + ("text-embedding-3-large", true) => Self::Large512, + (_, true) => panic!("unsupported dimensions with non-large model"), + ("text-embedding-3-large", false) => Self::Large, + ("text-embedding-3-small", false) => Self::Small, + ("text-embedding-ada-002", false) => Self::Ada, + (_, false) => panic!("unsupported model"), + } + } +} + +fn openai_responses() -> &'static OpenAiResponses { + static OPENAI_RESPONSES: std::sync::OnceLock = std::sync::OnceLock::new(); + OPENAI_RESPONSES.get_or_init(|| { + // json file that was compressed with gzip + // decompress with `gzip --keep -d openai_responses.json.gz` + // recompress with `gzip --keep -c openai_responses.json > openai_responses.json.gz` + let compressed_responses = include_bytes!("openai_responses.json.gz"); + let mut responses = Vec::new(); + let mut decoder = flate2::write::GzDecoder::new(&mut responses); + + decoder.write_all(compressed_responses).unwrap(); + drop(decoder); + serde_json::from_slice(&responses).unwrap() + }) +} + +async fn create_mock_with_template( + document_template: &str, + model_dimensions: ModelDimensions, + fallible: bool, +) -> (MockServer, Value) { + let mock_server = MockServer::start().await; + const API_KEY: &str = "my-api-key"; + const API_KEY_BEARER: &str = "Bearer my-api-key"; + + let attempt = AtomicU32::new(0); + + Mock::given(method("POST")) + .and(path("/")) + .respond_with(move |req: &Request| { + // 0. maybe return 500 + if fallible { + let attempt = attempt.fetch_add(1, Ordering::Relaxed); + let failed = matches!(attempt % 4, 0 | 1 | 3); + if failed { + return ResponseTemplate::new(503).set_body_json(json!({ + "error": { + "message": "come back later", + "type": "come_back_later" + } + })) + } + } + // 1. check API key + match req.headers.get("Authorization") { + Some(api_key) if api_key == API_KEY_BEARER => { + {} + } + Some(api_key) => { + let api_key = api_key.to_str().unwrap(); + return ResponseTemplate::new(401).set_body_json( + json!( + { + "error": { + "message": format!("Incorrect API key provided: {api_key}. You can find your API key at https://platform.openai.com/account/api-keys."), + "type": "invalid_request_error", + "param": serde_json::Value::Null, + "code": "invalid_api_key" + } + } + ), + ) + } + None => { + return ResponseTemplate::new(401).set_body_json( + json!( + { + "error": { + "message": "You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY), or as the password field (with blank username) if you're accessing the API from your browser and are prompted for a username and password. You can obtain an API key from https://platform.openai.com/account/api-keys.", + "type": "invalid_request_error", + "param": serde_json::Value::Null, + "code": serde_json::Value::Null + } + } + ), + ) + } + } + // 2. parse text inputs + let query: serde_json::Value = match req.body_json() { + Ok(query) => query, + Err(_error) => return ResponseTemplate::new(400).set_body_json( + json!( + { + "error": { + "message": "We could not parse the JSON body of your request. (HINT: This likely means you aren't using your HTTP library correctly. The OpenAI API expects a JSON payload, but what was sent was not valid JSON. If you have trouble figuring out how to fix this, please contact us through our help center at help.openai.com.)", + "type": "invalid_request_error", + "param": serde_json::Value::Null, + "code": serde_json::Value::Null + } + } + ) + ) + }; + let query_model_dimensions = ModelDimensions::from_request(&query); + if query_model_dimensions != model_dimensions { + return ResponseTemplate::new(400).set_body_json(json!({ + "error": { + "message": format!("Expected {model_dimensions:?}, got {query_model_dimensions:?}"), + "type": "invalid_model_dimensions", + "query": query, + } + })) + } + + // 3. for each text, find embedding in responses + let serde_json::Value::Array(inputs) = &query["input"] else { + return ResponseTemplate::new(400).set_body_json(json!({ + "error": { + "message": "Unexpected `input` value", + "type": "test_response", + "query": query + } + })) + }; + + let mut embeddings = Vec::new(); + + for input in inputs { + let serde_json::Value::String(input) = input else { + return ResponseTemplate::new(400).set_body_json(json!({ + "error": { + "message": "Unexpected `input` value", + "type": "test_response", + "query": query + } + })) + }; + + let Some(embedding) = openai_responses().get(input, model_dimensions) else { + return ResponseTemplate::new(400).set_body_json(json!( + { + "error": { + "message": "Could not find embedding for text", + "text": input, + "model_dimensions": format!("{model_dimensions:?}"), + "type": "add_to_openai_responses_json_please", + "query": query, + } + } + )) + }; + + embeddings.push(embedding.to_vec()); + } + + let data : Vec<_> = embeddings.into_iter().enumerate().map(|(index, embedding)| json!({ + "object": "embedding", + "index": index, + "embedding": embedding, + })).collect(); + + // 4. produce output from embeddings + ResponseTemplate::new(200).set_body_json(json!({ + "object": "list", + "data": data, + "model": model_dimensions.model(), + "usage": { + "prompt_tokens": "[prompt_tokens]", + "total_tokens": "[total_tokens]" + } + })) + }) + .mount(&mock_server) + .await; + let url = mock_server.uri(); + + let mut embedder_settings = json!({ + "source": "openAi", + "url": url, + "apiKey": API_KEY, + "documentTemplate": document_template + }); + + model_dimensions.add_to_settings(&mut embedder_settings); + + (mock_server, embedder_settings) +} + +const DOGGO_TEMPLATE: &str = r#"{%- if doc.gender == "F" -%}Une chienne nommée {{doc.name}}, née en {{doc.birthyear}} + {%- else -%} + Un chien nommé {{doc.name}}, né en {{doc.birthyear}} + {%- endif %}, de race {{doc.breed}}."#; + +async fn create_mock() -> (MockServer, Value) { + create_mock_with_template(DOGGO_TEMPLATE, ModelDimensions::Large, false).await +} + +async fn create_mock_dimensions() -> (MockServer, Value) { + create_mock_with_template(DOGGO_TEMPLATE, ModelDimensions::Large512, false).await +} + +async fn create_mock_small_embedding_model() -> (MockServer, Value) { + create_mock_with_template(DOGGO_TEMPLATE, ModelDimensions::Small, false).await +} + +async fn create_mock_legacy_embedding_model() -> (MockServer, Value) { + create_mock_with_template(DOGGO_TEMPLATE, ModelDimensions::Ada, false).await +} + +async fn create_fallible_mock() -> (MockServer, Value) { + create_mock_with_template(DOGGO_TEMPLATE, ModelDimensions::Large, true).await +} + +// basic test "it works" +#[actix_rt::test] +async fn it_works() { + let (_mock, setting) = create_mock().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + snapshot!(task["status"], @r###""succeeded""###); + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + snapshot!(task, @r###" + { + "uid": 1, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + let (documents, _code) = index + .get_all_documents(GetAllDocumentsOptions { retrieve_vectors: true, ..Default::default() }) + .await; + snapshot!(json_string!(documents, {".results.*._vectors.default.embeddings" => "[vector]"}), @r###" + { + "results": [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + } + ], + "offset": 0, + "limit": 20, + "total": 4 + } + "###); + + let (response, code) = index + .search_post(json!({ + "q": "chien de chasse", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "petit chien", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "grand chien de berger des montagnes", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + } + ] + "###); +} + +// tokenize long text + +// "wrong parameters" + +#[actix_rt::test] +async fn bad_api_key() { + let (_mock, mut setting) = create_mock().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + + snapshot!(task, @r###" + { + "uid": 0, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // wrong API key + setting["apiKey"] = "doggo".into(); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + + snapshot!(task, @r###" + { + "uid": 1, + "indexUid": "doggo", + "status": "failed", + "type": "settingsUpdate", + "canceledBy": null, + "details": { + "embedders": { + "default": { + "source": "openAi", + "model": "text-embedding-3-large", + "apiKey": "XXX...", + "documentTemplate": "{%- if doc.gender == \"F\" -%}Une chienne nommée {{doc.name}}, née en {{doc.birthyear}}\n {%- else -%}\n Un chien nommé {{doc.name}}, né en {{doc.birthyear}}\n {%- endif %}, de race {{doc.breed}}.", + "url": "[url]" + } + } + }, + "error": { + "message": "While embedding documents for embedder `default`: user error: could not authenticate against OpenAI server\n - server replied with `{\"error\":{\"message\":\"Incorrect API key provided: Bearer doggo. You can find your API key at https://platform.openai.com/account/api-keys.\",\"type\":\"invalid_request_error\",\"param\":null,\"code\":\"invalid_api_key\"}}`\n - Hint: Check the `apiKey` parameter in the embedder configuration, and the `MEILI_OPENAI_API_KEY` and `OPENAI_API_KEY` environment variables", + "code": "vector_embedding_error", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#vector_embedding_error" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // no API key + setting.as_object_mut().unwrap().remove("apiKey"); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + snapshot!(task, @r###" + { + "uid": 2, + "indexUid": "doggo", + "status": "failed", + "type": "settingsUpdate", + "canceledBy": null, + "details": { + "embedders": { + "default": { + "source": "openAi", + "model": "text-embedding-3-large", + "documentTemplate": "{%- if doc.gender == \"F\" -%}Une chienne nommée {{doc.name}}, née en {{doc.birthyear}}\n {%- else -%}\n Un chien nommé {{doc.name}}, né en {{doc.birthyear}}\n {%- endif %}, de race {{doc.breed}}.", + "url": "[url]" + } + } + }, + "error": { + "message": "While embedding documents for embedder `default`: user error: could not authenticate against OpenAI server\n - server replied with `{\"error\":{\"message\":\"You didn't provide an API key. You need to provide your API key in an Authorization header using Bearer auth (i.e. Authorization: Bearer YOUR_KEY), or as the password field (with blank username) if you're accessing the API from your browser and are prompted for a username and password. You can obtain an API key from https://platform.openai.com/account/api-keys.\",\"type\":\"invalid_request_error\",\"param\":null,\"code\":null}}`\n - Hint: Check the `apiKey` parameter in the embedder configuration, and the `MEILI_OPENAI_API_KEY` and `OPENAI_API_KEY` environment variables", + "code": "vector_embedding_error", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#vector_embedding_error" + }, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // not a string API key + setting["apiKey"] = 42.into(); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"400 Bad Request"); + snapshot!(response, @r###" + { + "message": "Invalid value type at `.embedders.default.apiKey`: expected a string, but found a positive integer: `42`", + "code": "invalid_settings_embedders", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_embedders" + } + "###); +} + +// one test with wrong model +#[actix_rt::test] +async fn bad_model() { + let (_mock, mut setting) = create_mock().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + + snapshot!(task, @r###" + { + "uid": 0, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // wrong model + setting["model"] = "doggo".into(); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"400 Bad Request"); + + snapshot!(response, @r###" + { + "message": "`.embedders.default.model`: Invalid model `doggo` for OpenAI. Supported models: [\"text-embedding-ada-002\", \"text-embedding-3-small\", \"text-embedding-3-large\"]", + "code": "invalid_settings_embedders", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_embedders" + } + "###); + + // not a string model + setting["model"] = 42.into(); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"400 Bad Request"); + snapshot!(response, @r###" + { + "message": "Invalid value type at `.embedders.default.model`: expected a string, but found a positive integer: `42`", + "code": "invalid_settings_embedders", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_embedders" + } + "###); +} + +#[actix_rt::test] +async fn bad_dimensions() { + let (_mock, mut setting) = create_mock().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + + snapshot!(task, @r###" + { + "uid": 0, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + // null dimensions + setting["dimensions"] = 0.into(); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"400 Bad Request"); + + snapshot!(response, @r###" + { + "message": "`.embedders.default.dimensions`: `dimensions` cannot be zero", + "code": "invalid_settings_embedders", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_embedders" + } + "###); + + // negative dimensions + setting["dimensions"] = (-42).into(); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"400 Bad Request"); + snapshot!(response, @r###" + { + "message": "Invalid value type at `.embedders.default.dimensions`: expected a positive integer, but found a negative integer: `-42`", + "code": "invalid_settings_embedders", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_embedders" + } + "###); + + // huge dimensions + setting["dimensions"] = (42_000_000).into(); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"400 Bad Request"); + snapshot!(response, @r###" + { + "message": "`.embedders.default.dimensions`: Model `text-embedding-3-large` does not support overriding its dimensions to a value higher than 3072. Found 42000000", + "code": "invalid_settings_embedders", + "type": "invalid_request", + "link": "https://docs.meilisearch.com/errors#invalid_settings_embedders" + } + "###); +} + +// one test with changed dimensions +#[actix_rt::test] +async fn smaller_dimensions() { + let (_mock, setting) = create_mock_dimensions().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + snapshot!(task["status"], @r###""succeeded""###); + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + snapshot!(task, @r###" + { + "uid": 1, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + let (documents, _code) = index + .get_all_documents(GetAllDocumentsOptions { retrieve_vectors: true, ..Default::default() }) + .await; + snapshot!(json_string!(documents, {".results.*._vectors.default.embeddings" => "[vector]"}), @r###" + { + "results": [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + } + ], + "offset": 0, + "limit": 20, + "total": 4 + } + "###); + + let (response, code) = index + .search_post(json!({ + "q": "chien de chasse", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "petit chien", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "grand chien de berger des montagnes", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + } + ] + "###); +} + +// one test with different models +#[actix_rt::test] +async fn small_embedding_model() { + let (_mock, setting) = create_mock_small_embedding_model().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + snapshot!(task["status"], @r###""succeeded""###); + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + snapshot!(task, @r###" + { + "uid": 1, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + let (documents, _code) = index + .get_all_documents(GetAllDocumentsOptions { retrieve_vectors: true, ..Default::default() }) + .await; + snapshot!(json_string!(documents, {".results.*._vectors.default.embeddings" => "[vector]"}), @r###" + { + "results": [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + } + ], + "offset": 0, + "limit": 20, + "total": 4 + } + "###); + + let (response, code) = index + .search_post(json!({ + "q": "chien de chasse", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "petit chien", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "grand chien de berger des montagnes", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + } + ] + "###); +} + +#[actix_rt::test] +async fn legacy_embedding_model() { + let (_mock, setting) = create_mock_legacy_embedding_model().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + snapshot!(task["status"], @r###""succeeded""###); + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + snapshot!(task, @r###" + { + "uid": 1, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + let (documents, _code) = index + .get_all_documents(GetAllDocumentsOptions { retrieve_vectors: true, ..Default::default() }) + .await; + snapshot!(json_string!(documents, {".results.*._vectors.default.embeddings" => "[vector]"}), @r###" + { + "results": [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + } + ], + "offset": 0, + "limit": 20, + "total": 4 + } + "###); + + let (response, code) = index + .search_post(json!({ + "q": "chien de chasse", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "petit chien", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "grand chien de berger des montagnes", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + } + ] + "###); +} + +// test with a server that responds 500 on 3 out of 4 calls +#[actix_rt::test] +async fn it_still_works() { + let (_mock, setting) = create_fallible_mock().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + snapshot!(task["status"], @r###""succeeded""###); + let documents = json!([ + {"id": 0, "name": "kefir", "gender": "M", "birthyear": 2023, "breed": "Patou"}, + {"id": 1, "name": "Intel", "gender": "M", "birthyear": 2011, "breed": "Beagle"}, + {"id": 2, "name": "Vénus", "gender": "F", "birthyear": 2003, "breed": "Jack Russel Terrier"}, + {"id": 3, "name": "Max", "gender": "M", "birthyear": 1995, "breed": "Labrador Retriever"}, + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + snapshot!(task, @r###" + { + "uid": 1, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 4, + "indexedDocuments": 4 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + let (documents, _code) = index + .get_all_documents(GetAllDocumentsOptions { retrieve_vectors: true, ..Default::default() }) + .await; + snapshot!(json_string!(documents, {".results.*._vectors.default.embeddings" => "[vector]"}), @r###" + { + "results": [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever", + "_vectors": { + "default": { + "embeddings": "[vector]", + "regenerate": true + } + } + } + ], + "offset": 0, + "limit": 20, + "total": 4 + } + "###); + + let (response, code) = index + .search_post(json!({ + "q": "chien de chasse", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "petit chien", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + }, + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + } + ] + "###); + + let (response, code) = index + .search_post(json!({ + "q": "grand chien de berger des montagnes", + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 0, + "name": "kefir", + "gender": "M", + "birthyear": 2023, + "breed": "Patou" + }, + { + "id": 1, + "name": "Intel", + "gender": "M", + "birthyear": 2011, + "breed": "Beagle" + }, + { + "id": 3, + "name": "Max", + "gender": "M", + "birthyear": 1995, + "breed": "Labrador Retriever" + }, + { + "id": 2, + "name": "Vénus", + "gender": "F", + "birthyear": 2003, + "breed": "Jack Russel Terrier" + } + ] + "###); +} +// test with a server that wrongly responds 400 diff --git a/meilisearch/tests/vector/rest.rs b/meilisearch/tests/vector/rest.rs index fe72ad428..75b0cf70d 100644 --- a/meilisearch/tests/vector/rest.rs +++ b/meilisearch/tests/vector/rest.rs @@ -5,9 +5,9 @@ use reqwest::IntoUrl; use wiremock::matchers::{method, path}; use wiremock::{Mock, MockServer, Request, ResponseTemplate}; -use crate::common::{Server, Value}; +use crate::common::Value; use crate::json; -use crate::vector::GetAllDocumentsOptions; +use crate::vector::{get_server_vector, GetAllDocumentsOptions}; async fn create_mock() -> (MockServer, Value) { let mock_server = MockServer::start().await; @@ -265,22 +265,6 @@ async fn dummy_testing_the_mock() { snapshot!(body, @r###"{"data":[4,4,4]}"###); } -async fn get_server_vector() -> Server { - let server = Server::new().await; - let (value, code) = server.set_features(json!({"vectorStore": true})).await; - snapshot!(code, @"200 OK"); - snapshot!(value, @r###" - { - "vectorStore": true, - "metrics": false, - "logsRoute": false, - "editDocumentsByFunction": false, - "containsFilter": false - } - "###); - server -} - #[actix_rt::test] async fn bad_request() { let (mock, _setting) = create_mock().await; From 9d6efd92d2bd43107377e4f2d1e8457dd992f8d7 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 15:02:27 +0200 Subject: [PATCH 12/26] new assets for tokenized test --- meilisearch/tests/vector/intel_gen.txt.gz | Bin 0 -> 6247 bytes .../vector/openai_tokenized_responses.json.gz | Bin 0 -> 21117 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 meilisearch/tests/vector/intel_gen.txt.gz create mode 100644 meilisearch/tests/vector/openai_tokenized_responses.json.gz diff --git a/meilisearch/tests/vector/intel_gen.txt.gz b/meilisearch/tests/vector/intel_gen.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..115eafea511612ad108ac96f51cd4b3ecdf6fd79 GIT binary patch literal 6247 zcmV-t7?|fDiwFoN3#n!R18Ht_Wo%z(Wo|BXcys`TTV0dmHj;erU%|I|k^4Wiee1I$ zZr2gJbK$s0NQ6XK{5pVajr{8`Gpj(dd%STk_H;J|0)?uqtgOf1OrWgX8k45jJA^Yrr8jMKS~O_@_pOY;c*y);V~n>IXOUw%(Z*IcHsG}E;yslPX2 zY@7Iur72T$&gs@IT;rNk#2+5rgje>xt#b`Z)3j|Xj2CO{FDwB`*_0vqU_SG@%7~&uuBXD=gG}E<+f>4S=M|m4c^|&5eGTF{ERj&k_zn8W_g*+w4@A6mEy0ldmE?1Q#V7%xVKYtkMK@i ze_pZDf24AWc{E>oOu5&E;&=3bFviEhpW=JW&!)g^(}<11UJKk7pMaGfArIP@d_5yrc|c;I+ft z$AuRAAGjiXht3p6GdoseRCGOddr#HN6)D`!0-KdJ!z|{aFh*GtuMitk*kLIwnsVm8 zmXLd#bgW_6#@Rf!Oe;<|uMDrUMIUT%AE$?H7Y=e;!!7c0{(R0c{t2^x<@Lr(jtlqI zx4J+Wp3h)=vCy6H$=s#@TR##nQI~8$a+OcvRSR6b!;X7I%LyO1n_ALf!BS>(tA9)j z-`&zadTPXH@J~mp4h~$*$L#^&$~y2x#E_mV(Z`EfNN#Wr*>GwG!d=%Mj=GL5>@zkK zBYSH8nBcyOzk!i;<=^E^IC>XnL|I$S^1o}sE#CS-=N23~Qp%{O=83zVV~y3CjS+^K_56 zgEq$5eFf&b9Zc~EH-3B_6Mn=+z5I6d&6O_Aau9~glk4S3H#FQ~K8VEQaboDTc1{A6 zdn->*$qjMt*PP7|<^#DJvn0j_<9q2&`z`??Gq;JqwdRm8*3uo~JBKv- z2@yr7rrVaK#&R!K8~oXA$J!b;C3WJz99kNp{yQ;?mQo*wWjS&;qWS zzGK!p(fM>ZVw1ayCs+I{Pe8hpIj7Pe;h;~$xo|B6$Ea;go>fXA;xH15r&!0YCC)nA z0}d96R7iw&X$&G6K(6aIW~=qw4=-a~)?viCZw`EA&Ug=B!(SqF$4}Vxu=E#Tg?C{f zu+=iy40|v9)dfJ(dVB*=CnTqu^?wTULV%$eaXiamf}A#1#5v@-4dWDzmJDLh;qGZ{ zX`z#21KVwnwTShW5D*9qy3&cCeC?F`&k4By6f2nYnGqymTR`w`mUI$!LH@b)Ar0T< z%mqg14K116H)mEN4;kKHltB@&b+t~LoCZq;H9!KA0wahF?J$iXmf7w?sqHrs!WPT~J~g)T769}kVF_bOZw*P|<>{O` z5tX#~q#PpBo5pc^4@6H`gqDAVCrvXwVugR)x4rj5!bdjgf%iK?K(=c$}Uu@Db)*-?97XG$wiqaFJ_sI5v;8Y093i- zOzkuPFzemAZ(=|C0k?-N!Ti;{vn~KV=Ci*rfiQy!ih7#F88sNG-VeH+PcQ#H(|riU zm+thDD~NluW@&EVVvFMl_cixx>CEF{27~=ArImSFEZwrGBB&9Kd2K%`nO2g;h1#%$ zFXouq@`HsGp%^D>!Bvr0gl?9_SV-LClQiUR0p|%m5#G27#Lx%>_RS5zdc=x!1G*{E zIq5O-N?gj*)d^fh1falT!O<&jLUsoC2J5VU{@I)R@*KM9b-apnF-!Kh3Ao%bUz1D_ z-;8tpLQaguRvMgkzQBeE(AaJOP11(je3InDC1u50`o_NhfyrQWcA)U3=_ag$cXc5f zNxLf%V=HCqm3A%FaU<)9j5b>M)NoFVk;uJN@v;po7&$!?AG%`3VtpyzVljk6tpX{r zB}?SYf5B*-b}Hh!98lG%4E>D72;(|cM&~yGCopjG`%_9ju&|BpAMoYEXB=I_CNi*C ze-I^{9h1zGtG5i49xuD?%nTt(8pD8N?w?&Fkn<}*@cIiA6E+5;^g|6vuSHc{*638Q zAxmaNeXqng-J&Y&id?)i+`9}gQV9HHRt6KfNog*zYGI!W zfnBGode0v5qyd7n3yLR1Dk)KCaJ8SZ$A3jP1Jd#+<^=NRg#?QtZPdo4!9)l^?SuQ0R^~UqtSGK^qt(S`q`lM2 z-=p)_z*{g5afm2Y?f<4W0#OB*Z~^Qic7vQ?3G*F2PZWIJy!BAzRIt1v_&XNmj~eSD zJSV@)TD039kyLYHt#eR!L;-mx-88kTWPqaD*B?_FU53RGWP>YpTpB@GYdWZtbs!ko z*s1wrC4w>8tH`doV^ct7AM#fV`CAw)kyB**;S6VrUIow6uD_>H_3TV>n~4496!bpU z+N}a5{uA2|)!PJ$3?Q}w#q2ajQS!GfcO0TdCEXrgXQjYPzYc}J&Pu9(tfo3^byyWHcC9;*`0#ylG;ayu{c!i;xS{j@FqPmzru<5e^Nr$f9H6}-*?M9Mv`zC zL{K?giRp)7NNq7gj#CA`Lmq%NO6(>jzxM=MKQ1a23}A$1i~&jB$HgcDUu`#A2yP)z zSx(g>ztdtQ0WdJ7sLZ`<<>X9N1y{u+<}&j1yd+&s_5W!yLM9AL%)*5!!N87J!(Up@ zL6jk?F7aC7s}~7T7mutS9)dM6W>|T)S^<_sS{)?!84i6go+yusj1oIA$(sfM zn2RTKJ+yRBYo%C586`Lxl{aFCi0_|Ytj6fg#N&-&YU%E6!(Ciryjnbg`=ESq!23yg zwYqD#=uqB3Ib?H@$bMaxX_VRu;+f@x@2NIxu0TL;^Gi$dP~uabyxeS)(Y{Bx-2@w8 zMH0H=?G{)9%z&fQL4BVll?%2h1BpwIXFj5g)z0tg{a7q->{!i=yxwjsbU9v7chB>hScw~Yue#YIsHe3Tr|qOZ3Y@&P zckCUVwC#iO@oK)`S3Mw{jSf3FQU8BT2E1Kpr$-G|*PVRw%a9^=K^zv92 z@*(S)4wKpj0^-+C(Wk5zUGlk8D0!>xu6j2VqfEZq5)zK*x{~fRNP$nvXlJR-oAM)* z*|qhl6tjfqjgzH|Fp!z9-i)@i;kLqE~DkXB_o+jT~Gx-=5a4?JdQ7C#ijhqre9#przid4a#Q}PHi?trHY$EwYZOt zs}(j)8{UaBezvX+FqkE0knpK^f3Oc=@%|>`IwNks3%Hjbr|C}Caf#A>yfm5v>-aHx zWkhL~A6w{hmh~3UfTv|aw}N{)NE*#aTaWT91A4ax9*Q|+0!&(@M#kKQS*i708;l~J zXKoBm3~qP}Enh1p@baJ7%pANH%=FG!OOLzS%wMY*A~NeCN9q*~FtoozIyz%Z!n#y0 z%1mc#oqH-~=Rg`A4$KXU9mFU(y61DOht>8FNv$k9pk{s8pH)pGDM}t#=TmL657rf# zrE>o)Pdk)Iu4@qZH-af(%(K=MSMz#7WgfY%9p8RpXF)%eU1AB?`VCYA+fk zwm+=%*2`{Oz55+ed6x84k%@rB!HO?l-eNnduXs_&bni$NQJn>zfDHsbZxS?8^t{9k z!-NT~4Ga*LRG<5`>c$u0P0xlt&z^?b2H2(|bigmQy+vL0zp?WdjhFOsQEWXDWa|lS!wd9%p}io=BalWKYBl};1CZI~kQd<8@yZP;wMn@QE|PCfWGU*mF}f4E z?7&i5W?XbpMJfz9aFPz8LLtz^GnqQdZw~#aGv6 z%D8w_FAlR6`<8fo7jHjVpjuW;&c!5E8u@j%j)PuK_MSpE-`Syv=KnGvSFrp(Lw+X#5DHIe|BXnGP0Ft_Amufp##Dg2Pr zb_T+uKXn2T;OTNVPu3l6X$R%YHxIAPx+llPr>f;PwcZCO#;asBbBe^ZlO-H-X(@OB z1}oaUg`22|x_hLS$9j^u!{i-;fLsnwg&7n=*%I$-vwJ_QWz9XXj{1 zB`*jQ=?qm0bD~i+e_{xLQ*?51_sx@!Z{X=nA?oUSj`A^`aSQBxZ=chk&xcqtXVk%7u(2vQ8poOp?){p1;Z%o-S766>nJvA5~w z9i*zt%^g#S)>L>}^bAufH0Z5@hEC{~n4zqKnHGY|Y)1&nui^$U@r_E2A$F>T}o zr@8b&9WHYv3G(&88o9Cg&f6`vLa)V4^iR_ywNDB&?jbxw=<`PdF+kh{C_VX1jdeeM zv%JTgY%;}i1W<+IXngIjL_n+<9;U2uK0?cFv|nz*eg_VCfBlOjL5&$;DC_*lC=w^b z${aa(5_C-ppM9!Jl&DPpW>0XQy;P1XSuxwCxMg%D2)+8qIqHxK2(ubwyW^Q1TMo+9 z!cwvyn2nWPKII_oR%Iw6Vx>Z-3ul$OBF#Bc zwQD_}70UbEXRyFIsb5RvXw_y`wEHx*ig(L*W>2RS)^PRY&vusOdLKVhM%;=-+U zAN^*1UobY!jVL4Z2}!!OPSma`v(M*Dl2aTuP>Tcmii=4Dpk}7`xo=NaRsQ;+j650e zvqxRnPJNH^n?v{Gv|E;#hh;9)Tt_rHChkf`UPZxG9OI7c`8jS%%ErM(k?hXo*c|r@ zy+MZ8IuxCS(o)Vk{n;q}k!J@}_Xn1o+9M8U=8bA?E;)t1FpEpUVnI=9M{O4!2jSc| zI!O@%C$)DShK}y-(_!)|pA1vo``~=6SpZZ#`!ub3Af792ysP$&V4hJDTiNR$DwQ|p z92cHH#75jnB#)`+xe|;4AhAoP)lz=)@$S?| z;;#~7D(=>?(nHz9F~)L~@O`dyFIPcMbYl|lT@U#Cc5^-@PvEv`0jJY-_*@R;NXIho z0ry6|eJH>-!x%i7PHGvc7GQqC<4S_E_r)2tyV`?&x>7Gr1?C3(JwH`orssT|c$4aP z7=PbKR`!`zOD()dONt-sFr8}-WgnB;kh?B$3B|FvHcvh%hF(%jzfPRV*wr)JvSmBA z7B*pzNn!@D5g0!yuZjt?YHSX2SLbnOCOuN4PtOlE5A6FiN_bqjHLlQi0VH zyA$;3`kh)pK6J91;VxLRsl-2iM?!M{))&xp{67AwnHNOE&CAmdbMA+UAHS1pXzLe< z>ZJQ|F#A+XiHG;0$_ktQtjTh3RI4J6{w)e`_~msx;7MPb-J7rD?uS@w^Of_On;UE+ z9#pkc7S_JM3-J)=25tFs7okm6wNJ-Ks#K9_HFG=3w@KN=O6QzuW^RlNJcnI_GY9lz_N1a|n&hR4De`M?`9@EA#LM6yo1g<-<;?6w!6ud@e53&ufBPDW>ZvRw7vuIQK!^*y*BgE zRPUiql-jXmXtuJx%Lo5r_=#P6E5%zd$;Y>-Q`q=@225(Ewo086|1LRx(3TCAPRCl~ z_YDAc|59(>bB-0zy|=+XIgfq)<@n8xPr>R%Dm@TxHhubzk%!$r!D<>@ik471T6o-M RRBf!~{{R@~#GaHn008@U70>_x literal 0 HcmV?d00001 diff --git a/meilisearch/tests/vector/openai_tokenized_responses.json.gz b/meilisearch/tests/vector/openai_tokenized_responses.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..0c708448c6a01d062264a4b615ca69823a816615 GIT binary patch literal 21117 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 N{yzzmo+&IX0RYHKI)?xN literal 0 HcmV?d00001 From ab1ec9ca21178f193c199bd5a63a90d4aa2ac78f Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 15:01:34 +0200 Subject: [PATCH 13/26] Add tokenized test --- meilisearch/tests/vector/openai.rs | 194 +++++++++++++++++++++++------ 1 file changed, 153 insertions(+), 41 deletions(-) diff --git a/meilisearch/tests/vector/openai.rs b/meilisearch/tests/vector/openai.rs index 744f239bc..2bd90c3b9 100644 --- a/meilisearch/tests/vector/openai.rs +++ b/meilisearch/tests/vector/openai.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::io::Write; use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::OnceLock; use meili_snap::{json_string, snapshot}; use wiremock::matchers::{method, path}; @@ -21,6 +22,12 @@ struct OpenAiResponse { large_512: Option>, } +#[derive(serde::Deserialize)] +struct OpenAiTokenizedResponses { + tokens: Vec, + embedding: Vec, +} + impl OpenAiResponses { fn get(&self, text: &str, model_dimensions: ModelDimensions) -> Option<&[f32]> { let entry = self.0.get(text)?; @@ -81,7 +88,7 @@ impl ModelDimensions { } fn openai_responses() -> &'static OpenAiResponses { - static OPENAI_RESPONSES: std::sync::OnceLock = std::sync::OnceLock::new(); + static OPENAI_RESPONSES: OnceLock = OnceLock::new(); OPENAI_RESPONSES.get_or_init(|| { // json file that was compressed with gzip // decompress with `gzip --keep -d openai_responses.json.gz` @@ -96,6 +103,43 @@ fn openai_responses() -> &'static OpenAiResponses { }) } +fn openai_tokenized_responses() -> &'static OpenAiTokenizedResponses { + static OPENAI_TOKENIZED_RESPONSES: OnceLock = OnceLock::new(); + OPENAI_TOKENIZED_RESPONSES.get_or_init(|| { + // json file that was compressed with gzip + // decompress with `gzip --keep -d openai_tokenized_responses.json.gz` + // recompress with `gzip --keep -c openai_tokenized_responses.json > openai_tokenized_responses.json.gz` + let compressed_responses = include_bytes!("openai_tokenized_responses.json.gz"); + let mut responses = Vec::new(); + let mut decoder = flate2::write::GzDecoder::new(&mut responses); + + decoder.write_all(compressed_responses).unwrap(); + drop(decoder); + serde_json::from_slice(&responses).unwrap() + }) +} + +fn long_text() -> &'static str { + static LONG_TEXT: OnceLock = OnceLock::new(); + LONG_TEXT.get_or_init(|| { + // decompress with `gzip --keep -d intel_gen.txt.gz` + // recompress with `gzip --keep -c intel_gen.txt > intel_gen.txt.gz` + let compressed_long_text = include_bytes!("intel_gen.txt.gz"); + let mut long_text = Vec::new(); + let mut decoder = flate2::write::GzDecoder::new(&mut long_text); + + decoder.write_all(compressed_long_text).unwrap(); + drop(decoder); + let long_text = std::str::from_utf8(&long_text).unwrap(); + + long_text.repeat(3) + }) +} + +async fn create_mock_tokenized() -> (MockServer, Value) { + create_mock_with_template("{{doc.text}}", ModelDimensions::Large, false).await +} + async fn create_mock_with_template( document_template: &str, model_dimensions: ModelDimensions, @@ -176,55 +220,62 @@ async fn create_mock_with_template( }; let query_model_dimensions = ModelDimensions::from_request(&query); if query_model_dimensions != model_dimensions { - return ResponseTemplate::new(400).set_body_json(json!({ - "error": { - "message": format!("Expected {model_dimensions:?}, got {query_model_dimensions:?}"), - "type": "invalid_model_dimensions", - "query": query, - } - })) + panic!("Expected {model_dimensions:?}, got {query_model_dimensions:?}") } // 3. for each text, find embedding in responses let serde_json::Value::Array(inputs) = &query["input"] else { - return ResponseTemplate::new(400).set_body_json(json!({ - "error": { - "message": "Unexpected `input` value", - "type": "test_response", - "query": query - } - })) + panic!("Unexpected `input` value") }; - let mut embeddings = Vec::new(); - - for input in inputs { - let serde_json::Value::String(input) = input else { - return ResponseTemplate::new(400).set_body_json(json!({ - "error": { - "message": "Unexpected `input` value", - "type": "test_response", - "query": query - } - })) - }; - - let Some(embedding) = openai_responses().get(input, model_dimensions) else { - return ResponseTemplate::new(400).set_body_json(json!( - { + let openai_tokenized_responses = openai_tokenized_responses(); + let embeddings = if inputs == openai_tokenized_responses.tokens.as_slice() { + vec![openai_tokenized_responses.embedding.clone()] + } else { + let mut embeddings = Vec::new(); + for input in inputs { + let serde_json::Value::String(input) = input else { + return ResponseTemplate::new(400).set_body_json(json!({ "error": { - "message": "Could not find embedding for text", - "text": input, - "model_dimensions": format!("{model_dimensions:?}"), - "type": "add_to_openai_responses_json_please", - "query": query, + "message": "Unexpected `input` value", + "type": "test_response", + "query": query } - } - )) - }; + })) + }; + + if input == long_text() { + return ResponseTemplate::new(400).set_body_json(json!( + { + "error": { + "message": "This model's maximum context length is 8192 tokens, however you requested 10554 tokens (10554 in your prompt; 0 for the completion). Please reduce your prompt; or completion length.", + "type": "invalid_request_error", + "param": null, + "code": null, + } + } + )); + } + + let Some(embedding) = openai_responses().get(input, model_dimensions) else { + return ResponseTemplate::new(404).set_body_json(json!( + { + "error": { + "message": "Could not find embedding for text", + "text": input, + "model_dimensions": format!("{model_dimensions:?}"), + "type": "add_to_openai_responses_json_please", + "query": query, + } + } + )) + }; + + embeddings.push(embedding.to_vec()); + } + embeddings + }; - embeddings.push(embedding.to_vec()); - } let data : Vec<_> = embeddings.into_iter().enumerate().map(|(index, embedding)| json!({ "object": "embedding", @@ -517,6 +568,67 @@ async fn it_works() { // tokenize long text +// basic test "it works" +#[actix_rt::test] +async fn tokenize_long_text() { + let (_mock, setting) = create_mock_tokenized().await; + let server = get_server_vector().await; + let index = server.index("doggo"); + + let (response, code) = index + .update_settings(json!({ + "embedders": { + "default": setting, + }, + })) + .await; + snapshot!(code, @"202 Accepted"); + let task = server.wait_task(response.uid()).await; + snapshot!(task["status"], @r###""succeeded""###); + let documents = json!([ + {"id": 0, "text": long_text()} + ]); + let (value, code) = index.add_documents(documents, None).await; + snapshot!(code, @"202 Accepted"); + let task = index.wait_task(value.uid()).await; + snapshot!(task, @r###" + { + "uid": 1, + "indexUid": "doggo", + "status": "succeeded", + "type": "documentAdditionOrUpdate", + "canceledBy": null, + "details": { + "receivedDocuments": 1, + "indexedDocuments": 1 + }, + "error": null, + "duration": "[duration]", + "enqueuedAt": "[date]", + "startedAt": "[date]", + "finishedAt": "[date]" + } + "###); + + let (response, code) = index + .search_post(json!({ + "q": "grand chien de berger des montagnes", + "showRankingScore": true, + "attributesToRetrieve": ["id"], + "hybrid": {"semanticRatio": 1.0} + })) + .await; + snapshot!(code, @"200 OK"); + snapshot!(json_string!(response["hits"]), @r###" + [ + { + "id": 0, + "_rankingScore": 0.07944583892822266 + } + ] + "###); +} + // "wrong parameters" #[actix_rt::test] From 48f7329a83961e25f9ef1e4d2f641d9954a81516 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 17:11:28 +0200 Subject: [PATCH 14/26] Specify index_mapper on `IndexStats` --- index-scheduler/src/index_mapper/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index-scheduler/src/index_mapper/mod.rs b/index-scheduler/src/index_mapper/mod.rs index 14908120c..3cccb5a69 100644 --- a/index-scheduler/src/index_mapper/mod.rs +++ b/index-scheduler/src/index_mapper/mod.rs @@ -108,8 +108,10 @@ pub struct IndexStats { /// Association of every field name with the number of times it occurs in the documents. pub field_distribution: FieldDistribution, /// Creation date of the index. + #[serde(with = "time::serde::rfc3339")] pub created_at: OffsetDateTime, /// Date of the last update of the index. + #[serde(with = "time::serde::rfc3339")] pub updated_at: OffsetDateTime, } From 9ef710cad42b08d362e0a3dffd85558dcb8c3768 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 17:11:55 +0200 Subject: [PATCH 15/26] Use wrapper that forces the desired date format --- milli/src/index.rs | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/milli/src/index.rs b/milli/src/index.rs index 3a2f3169c..512e911aa 100644 --- a/milli/src/index.rs +++ b/milli/src/index.rs @@ -9,7 +9,6 @@ use heed::{CompactionOption, Database, RoTxn, RwTxn, Unspecified}; use roaring::RoaringBitmap; use rstar::RTree; use serde::{Deserialize, Serialize}; -use time::OffsetDateTime; use crate::documents::PrimaryKey; use crate::error::{InternalError, UserError}; @@ -173,8 +172,8 @@ impl Index { pub fn new_with_creation_dates>( mut options: heed::EnvOpenOptions, path: P, - created_at: OffsetDateTime, - updated_at: OffsetDateTime, + created_at: time::OffsetDateTime, + updated_at: time::OffsetDateTime, ) -> Result { use db_name::*; @@ -256,22 +255,22 @@ impl Index { } pub fn new>(options: heed::EnvOpenOptions, path: P) -> Result { - let now = OffsetDateTime::now_utc(); + let now = time::OffsetDateTime::now_utc(); Self::new_with_creation_dates(options, path, now, now) } fn set_creation_dates( env: &heed::Env, main: Database, - created_at: OffsetDateTime, - updated_at: OffsetDateTime, + created_at: time::OffsetDateTime, + updated_at: time::OffsetDateTime, ) -> heed::Result<()> { let mut txn = env.write_txn()?; // The db was just created, we update its metadata with the relevant information. let main = main.remap_types::>(); if main.get(&txn, main_key::CREATED_AT_KEY)?.is_none() { - main.put(&mut txn, main_key::UPDATED_AT_KEY, &updated_at)?; - main.put(&mut txn, main_key::CREATED_AT_KEY, &created_at)?; + main.put(&mut txn, main_key::UPDATED_AT_KEY, &OffsetDateTime(updated_at))?; + main.put(&mut txn, main_key::CREATED_AT_KEY, &OffsetDateTime(created_at))?; txn.commit()?; } Ok(()) @@ -371,7 +370,7 @@ impl Index { wtxn: &mut RwTxn<'_>, primary_key: &str, ) -> heed::Result<()> { - self.set_updated_at(wtxn, &OffsetDateTime::now_utc())?; + self.set_updated_at(wtxn, &time::OffsetDateTime::now_utc())?; self.main.remap_types::().put(wtxn, main_key::PRIMARY_KEY_KEY, primary_key) } @@ -1323,7 +1322,7 @@ impl Index { } /// Returns the index creation time. - pub fn created_at(&self, rtxn: &RoTxn<'_>) -> Result { + pub fn created_at(&self, rtxn: &RoTxn<'_>) -> Result { Ok(self .main .remap_types::>() @@ -1331,11 +1330,12 @@ impl Index { .ok_or(InternalError::DatabaseMissingEntry { db_name: db_name::MAIN, key: Some(main_key::CREATED_AT_KEY), - })?) + })? + .0) } /// Returns the index last updated time. - pub fn updated_at(&self, rtxn: &RoTxn<'_>) -> Result { + pub fn updated_at(&self, rtxn: &RoTxn<'_>) -> Result { Ok(self .main .remap_types::>() @@ -1343,18 +1343,19 @@ impl Index { .ok_or(InternalError::DatabaseMissingEntry { db_name: db_name::MAIN, key: Some(main_key::UPDATED_AT_KEY), - })?) + })? + .0) } pub(crate) fn set_updated_at( &self, wtxn: &mut RwTxn<'_>, - time: &OffsetDateTime, + time: &time::OffsetDateTime, ) -> heed::Result<()> { self.main.remap_types::>().put( wtxn, main_key::UPDATED_AT_KEY, - time, + &OffsetDateTime(*time), ) } @@ -1681,6 +1682,10 @@ pub struct IndexEmbeddingConfig { pub user_provided: RoaringBitmap, } +#[derive(Serialize, Deserialize)] +#[serde(transparent)] +struct OffsetDateTime(#[serde(with = "time::serde::rfc3339")] time::OffsetDateTime); + #[cfg(test)] pub(crate) mod tests { use std::collections::HashSet; From 72b9005344643edd28adacaa074892eee5d307c6 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 17:57:13 +0200 Subject: [PATCH 16/26] Redact uid for Value --- meilisearch/tests/common/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/meilisearch/tests/common/mod.rs b/meilisearch/tests/common/mod.rs index ee1d8aa6e..0c4e8e25c 100644 --- a/meilisearch/tests/common/mod.rs +++ b/meilisearch/tests/common/mod.rs @@ -81,6 +81,7 @@ impl Display for Value { f, "{}", json_string!(self, { + ".uid" => "[uid]", ".enqueuedAt" => "[date]", ".startedAt" => "[date]", ".finishedAt" => "[date]", From 8535dc0be2d6951c0f845b0341537d0305f1b712 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 17:57:32 +0200 Subject: [PATCH 17/26] Fix existing tests --- meilisearch/tests/documents/add_documents.rs | 16 ++++----- .../1.snap | 2 +- .../2.snap | 2 +- .../distinct_at_search_time/succeed.snap | 2 +- .../distinct_at_search_time/task-succeed.snap | 2 +- meilisearch/tests/tasks/mod.rs | 8 ++--- meilisearch/tests/vector/mod.rs | 24 ++++++------- meilisearch/tests/vector/rest.rs | 34 +++++++++---------- meilisearch/tests/vector/settings.rs | 2 +- .../document-added.snap | 2 +- .../document-deleted.snap | 2 +- .../settings-processed.snap | 2 +- 12 files changed, 49 insertions(+), 49 deletions(-) diff --git a/meilisearch/tests/documents/add_documents.rs b/meilisearch/tests/documents/add_documents.rs index 7c5f3efd3..819b2ddc2 100644 --- a/meilisearch/tests/documents/add_documents.rs +++ b/meilisearch/tests/documents/add_documents.rs @@ -1110,7 +1110,7 @@ async fn document_addition_with_huge_int_primary_key() { snapshot!(response, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1402,7 +1402,7 @@ async fn error_document_field_limit_reached_over_multiple_documents() { snapshot!(response, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1436,7 +1436,7 @@ async fn error_document_field_limit_reached_over_multiple_documents() { snapshot!(response, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "test", "status": "failed", "type": "documentAdditionOrUpdate", @@ -1485,7 +1485,7 @@ async fn error_document_field_limit_reached_in_one_nested_document() { snapshot!(response, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1528,7 +1528,7 @@ async fn error_document_field_limit_reached_over_multiple_documents_with_nested_ snapshot!(response, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1563,7 +1563,7 @@ async fn error_document_field_limit_reached_over_multiple_documents_with_nested_ snapshot!(response, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -2209,7 +2209,7 @@ async fn add_invalid_geo_and_then_settings() { let ret = index.wait_task(ret.uid()).await; snapshot!(ret, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -2231,7 +2231,7 @@ async fn add_invalid_geo_and_then_settings() { let ret = index.wait_task(ret.uid()).await; snapshot!(ret, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "test", "status": "failed", "type": "settingsUpdate", diff --git a/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/1.snap b/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/1.snap index 4b05d417a..2004eb036 100644 --- a/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/1.snap +++ b/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/1.snap @@ -2,7 +2,7 @@ source: meilisearch/tests/dumps/mod.rs --- { - "uid": 0, + "uid": "[uid]", "indexUid": "pets", "status": "succeeded", "type": "settingsUpdate", diff --git a/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/2.snap b/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/2.snap index 43971924b..8405a0461 100644 --- a/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/2.snap +++ b/meilisearch/tests/dumps/snapshots/mod.rs/generate_and_import_dump_containing_vectors/2.snap @@ -2,7 +2,7 @@ source: meilisearch/tests/dumps/mod.rs --- { - "uid": 1, + "uid": "[uid]", "indexUid": "pets", "status": "succeeded", "type": "documentAdditionOrUpdate", diff --git a/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap b/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap index 1b8190c42..64e48b6a5 100644 --- a/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap +++ b/meilisearch/tests/search/snapshots/distinct.rs/distinct_at_search_time/succeed.snap @@ -2,7 +2,7 @@ source: meilisearch/tests/search/distinct.rs --- { - "uid": 1, + "uid": "[uid]", "indexUid": "tamo", "status": "succeeded", "type": "settingsUpdate", diff --git a/meilisearch/tests/search/snapshots/errors.rs/distinct_at_search_time/task-succeed.snap b/meilisearch/tests/search/snapshots/errors.rs/distinct_at_search_time/task-succeed.snap index 903e96ffb..18532cba4 100644 --- a/meilisearch/tests/search/snapshots/errors.rs/distinct_at_search_time/task-succeed.snap +++ b/meilisearch/tests/search/snapshots/errors.rs/distinct_at_search_time/task-succeed.snap @@ -2,7 +2,7 @@ source: meilisearch/tests/search/errors.rs --- { - "uid": 0, + "uid": "[uid]", "indexUid": "tamo", "status": "succeeded", "type": "indexCreation", diff --git a/meilisearch/tests/tasks/mod.rs b/meilisearch/tests/tasks/mod.rs index f2ed76b6a..23ba669ca 100644 --- a/meilisearch/tests/tasks/mod.rs +++ b/meilisearch/tests/tasks/mod.rs @@ -744,7 +744,7 @@ async fn test_summarized_index_deletion() { snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "test", "status": "failed", "type": "indexDeletion", @@ -774,7 +774,7 @@ async fn test_summarized_index_deletion() { snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -796,7 +796,7 @@ async fn test_summarized_index_deletion() { snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "test", "status": "succeeded", "type": "indexDeletion", @@ -818,7 +818,7 @@ async fn test_summarized_index_deletion() { snapshot!(task, @r###" { - "uid": 3, + "uid": "[uid]", "indexUid": "test", "status": "failed", "type": "indexDeletion", diff --git a/meilisearch/tests/vector/mod.rs b/meilisearch/tests/vector/mod.rs index 9935c6330..0837fb1b8 100644 --- a/meilisearch/tests/vector/mod.rs +++ b/meilisearch/tests/vector/mod.rs @@ -235,7 +235,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -264,7 +264,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 3, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -294,7 +294,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 4, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -323,7 +323,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 5, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -352,7 +352,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 6, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -381,7 +381,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 7, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -422,7 +422,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 10, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -450,7 +450,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 11, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -478,7 +478,7 @@ async fn user_provided_embeddings_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 12, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -514,7 +514,7 @@ async fn user_provided_vectors_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -543,7 +543,7 @@ async fn user_provided_vectors_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 3, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -572,7 +572,7 @@ async fn user_provided_vectors_error() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 4, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", diff --git a/meilisearch/tests/vector/rest.rs b/meilisearch/tests/vector/rest.rs index 75b0cf70d..1a64eeb78 100644 --- a/meilisearch/tests/vector/rest.rs +++ b/meilisearch/tests/vector/rest.rs @@ -880,7 +880,7 @@ async fn bad_settings() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -925,7 +925,7 @@ async fn bad_settings() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -974,7 +974,7 @@ async fn add_vector_and_user_provided() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1070,7 +1070,7 @@ async fn server_returns_bad_request() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1109,7 +1109,7 @@ async fn server_returns_bad_request() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "settingsUpdate", @@ -1138,7 +1138,7 @@ async fn server_returns_bad_request() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "documentAdditionOrUpdate", @@ -1182,7 +1182,7 @@ async fn server_returns_bad_response() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1235,7 +1235,7 @@ async fn server_returns_bad_response() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1290,7 +1290,7 @@ async fn server_returns_bad_response() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1345,7 +1345,7 @@ async fn server_returns_bad_response() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 3, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1410,7 +1410,7 @@ async fn server_returns_bad_response() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 4, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1477,7 +1477,7 @@ async fn server_returns_multiple() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1582,7 +1582,7 @@ async fn server_single_input_returns_in_array() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1687,7 +1687,7 @@ async fn server_raw() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1784,7 +1784,7 @@ async fn server_custom_header() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1823,7 +1823,7 @@ async fn server_custom_header() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -1865,7 +1865,7 @@ async fn server_custom_header() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "settingsUpdate", diff --git a/meilisearch/tests/vector/settings.rs b/meilisearch/tests/vector/settings.rs index 8fdb858c3..0714a22ca 100644 --- a/meilisearch/tests/vector/settings.rs +++ b/meilisearch/tests/vector/settings.rs @@ -43,7 +43,7 @@ async fn update_embedder() { let ret = server.wait_task(response.uid()).await; snapshot!(ret, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "settingsUpdate", diff --git a/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-added.snap b/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-added.snap index 52d9ad38d..c4f1c0b25 100644 --- a/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-added.snap +++ b/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-added.snap @@ -2,7 +2,7 @@ source: meilisearch/tests/vector/mod.rs --- { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", diff --git a/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-deleted.snap b/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-deleted.snap index de02d0b1d..c4f1c0b25 100644 --- a/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-deleted.snap +++ b/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/document-deleted.snap @@ -2,7 +2,7 @@ source: meilisearch/tests/vector/mod.rs --- { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", diff --git a/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/settings-processed.snap b/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/settings-processed.snap index 316305fa8..08dbe3ee0 100644 --- a/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/settings-processed.snap +++ b/meilisearch/tests/vector/snapshots/mod.rs/add_remove_one_vector_4588/settings-processed.snap @@ -2,7 +2,7 @@ source: meilisearch/tests/vector/mod.rs --- { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "settingsUpdate", From 21aa430b5eabaf0578197837df18501f8b1205cf Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Wed, 31 Jul 2024 17:57:55 +0200 Subject: [PATCH 18/26] Fix openai tests --- meilisearch/tests/vector/openai.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/meilisearch/tests/vector/openai.rs b/meilisearch/tests/vector/openai.rs index 2bd90c3b9..f350abbe1 100644 --- a/meilisearch/tests/vector/openai.rs +++ b/meilisearch/tests/vector/openai.rs @@ -363,7 +363,7 @@ async fn it_works() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -593,7 +593,7 @@ async fn tokenize_long_text() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -649,7 +649,7 @@ async fn bad_api_key() { snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -681,7 +681,7 @@ async fn bad_api_key() { snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -724,7 +724,7 @@ async fn bad_api_key() { let task = server.wait_task(response.uid()).await; snapshot!(task, @r###" { - "uid": 2, + "uid": "[uid]", "indexUid": "doggo", "status": "failed", "type": "settingsUpdate", @@ -792,7 +792,7 @@ async fn bad_model() { snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -869,7 +869,7 @@ async fn bad_dimensions() { snapshot!(task, @r###" { - "uid": 0, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -976,7 +976,7 @@ async fn smaller_dimensions() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1207,7 +1207,7 @@ async fn small_embedding_model() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1437,7 +1437,7 @@ async fn legacy_embedding_model() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", @@ -1668,7 +1668,7 @@ async fn it_still_works() { let task = index.wait_task(value.uid()).await; snapshot!(task, @r###" { - "uid": 1, + "uid": "[uid]", "indexUid": "doggo", "status": "succeeded", "type": "documentAdditionOrUpdate", From e64d0e0ca860543ebcefa2a5de7f7de0c634159c Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 1 Aug 2024 18:32:45 +0200 Subject: [PATCH 19/26] use insert instead of push for bitmaps --- milli/src/update/index_documents/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/milli/src/update/index_documents/mod.rs b/milli/src/update/index_documents/mod.rs index 39919d94a..87c6bc6db 100644 --- a/milli/src/update/index_documents/mod.rs +++ b/milli/src/update/index_documents/mod.rs @@ -290,7 +290,7 @@ where match result? { DocumentEdition::Deleted(docid) => { - documents_to_remove.push(docid); + documents_to_remove.insert(docid); } DocumentEdition::Edited(new_document) => { documents_batch_builder.append_json_object(&new_document)?; From e3ef0ae19e415cce2cb12e4c5f7274374fdc45c5 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Tue, 6 Aug 2024 14:06:56 +0200 Subject: [PATCH 20/26] also intersect the universe for searchOnAttributes --- milli/src/search/new/db_cache.rs | 38 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/milli/src/search/new/db_cache.rs b/milli/src/search/new/db_cache.rs index d33058af1..d1d9d6d9a 100644 --- a/milli/src/search/new/db_cache.rs +++ b/milli/src/search/new/db_cache.rs @@ -110,18 +110,18 @@ impl<'ctx> DatabaseCache<'ctx> { .map_err(Into::into) } - fn get_value_from_keys<'v, K1, KC, DC>( + fn get_value_from_keys<'v, K1, KC>( txn: &'ctx RoTxn<'_>, cache_key: K1, db_keys: &'v [KC::EItem], cache: &mut FxHashMap>>, db: Database, + universe: Option<&RoaringBitmap>, merger: MergeFn, - ) -> Result> + ) -> Result> where K1: Copy + Eq + Hash, KC: BytesEncode<'v>, - DC: BytesDecodeOwned, KC::EItem: Sized, { if let Entry::Vacant(entry) = cache.entry(cache_key) { @@ -146,16 +146,22 @@ impl<'ctx> DatabaseCache<'ctx> { entry.insert(bitmap_ptr); } - match cache.get(&cache_key).unwrap() { - Some(Cow::Borrowed(bytes)) => DC::bytes_decode_owned(bytes) + let bitmap_bytes = match cache.get(&cache_key).unwrap() { + Some(Cow::Borrowed(bytes)) => bytes, + Some(Cow::Owned(bytes)) => bytes.as_slice(), + None => return Ok(None), + }; + + match (bitmap_bytes, universe) { + (bytes, Some(universe)) => { + CboRoaringBitmapCodec::intersection_with_serialized(bytes, universe) + .map(Some) + .map_err(Into::into) + } + (bytes, None) => CboRoaringBitmapCodec::bytes_decode_owned(bytes) .map(Some) .map_err(heed::Error::Decoding) .map_err(Into::into), - Some(Cow::Owned(bytes)) => DC::bytes_decode_owned(bytes) - .map(Some) - .map_err(heed::Error::Decoding) - .map_err(Into::into), - None => Ok(None), } } } @@ -207,12 +213,13 @@ impl<'ctx> SearchContext<'ctx> { let keys: Vec<_> = restricted_fids.tolerant.iter().map(|(fid, _)| (interned, *fid)).collect(); - DatabaseCache::get_value_from_keys::<_, _, CboRoaringBitmapCodec>( + DatabaseCache::get_value_from_keys::<_, _>( self.txn, word, &keys[..], &mut self.db_cache.word_docids, self.index.word_fid_docids.remap_data_type::(), + universe, merge_cbo_roaring_bitmaps, ) } @@ -238,12 +245,13 @@ impl<'ctx> SearchContext<'ctx> { let keys: Vec<_> = restricted_fids.exact.iter().map(|(fid, _)| (interned, *fid)).collect(); - DatabaseCache::get_value_from_keys::<_, _, CboRoaringBitmapCodec>( + DatabaseCache::get_value_from_keys::<_, _>( self.txn, word, &keys[..], &mut self.db_cache.exact_word_docids, self.index.word_fid_docids.remap_data_type::(), + universe, merge_cbo_roaring_bitmaps, ) } @@ -294,12 +302,13 @@ impl<'ctx> SearchContext<'ctx> { let keys: Vec<_> = restricted_fids.tolerant.iter().map(|(fid, _)| (interned, *fid)).collect(); - DatabaseCache::get_value_from_keys::<_, _, CboRoaringBitmapCodec>( + DatabaseCache::get_value_from_keys::<_, _>( self.txn, prefix, &keys[..], &mut self.db_cache.word_prefix_docids, self.index.word_prefix_fid_docids.remap_data_type::(), + universe, merge_cbo_roaring_bitmaps, ) } @@ -325,12 +334,13 @@ impl<'ctx> SearchContext<'ctx> { let keys: Vec<_> = restricted_fids.exact.iter().map(|(fid, _)| (interned, *fid)).collect(); - DatabaseCache::get_value_from_keys::<_, _, CboRoaringBitmapCodec>( + DatabaseCache::get_value_from_keys::<_, _>( self.txn, prefix, &keys[..], &mut self.db_cache.exact_word_prefix_docids, self.index.word_prefix_fid_docids.remap_data_type::(), + universe, merge_cbo_roaring_bitmaps, ) } From 2f10273d1418e42b401b62ce2abbcef0df89e8ae Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 8 Aug 2024 14:02:53 +0200 Subject: [PATCH 21/26] Group by normalized values, make sure you don't remove a value where there remains at still one value that normalizes towards it --- .../extract/extract_fid_docid_facet_values.rs | 100 +++++++++++++++--- 1 file changed, 83 insertions(+), 17 deletions(-) diff --git a/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs b/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs index 810fa26a9..cc9df70de 100644 --- a/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs +++ b/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs @@ -9,7 +9,7 @@ use std::result::Result as StdResult; use bytemuck::bytes_of; use grenad::Sorter; use heed::BytesEncode; -use itertools::{merge_join_by, EitherOrBoth}; +use itertools::{merge_join_by, EitherOrBoth, Itertools}; use ordered_float::OrderedFloat; use roaring::RoaringBitmap; use serde_json::{from_slice, Value}; @@ -401,36 +401,102 @@ where del_strings.dedup(); add_strings.dedup(); + let del_strings = del_strings.iter().chunk_by(|(normalized, _)| normalized); + let add_strings = add_strings.iter().chunk_by(|(normalized, _)| normalized); + let merged_strings_iter = itertools::merge_join_by( del_strings.into_iter().filter(|(n, _)| !n.is_empty()), add_strings.into_iter().filter(|(n, _)| !n.is_empty()), - |del, add| del.cmp(add), + |(normalized_del, _), (normalized_add, _)| normalized_del.cmp(normalized_add), ); // insert normalized and original facet string in sorter for eob in merged_strings_iter { key_buffer.truncate(TRUNCATE_SIZE); - match eob { - EitherOrBoth::Both(_, _) => (), // no need to touch anything - EitherOrBoth::Left((normalized, original)) => { - let truncated = truncate_string(normalized); + let (side, normalized, original) = match eob { + EitherOrBoth::Both((normalized, del), (_, add)) => { + let merged_strings_iter = + itertools::merge_join_by(del, add, |(_, original_del), (_, original_add)| { + original_del.cmp(original_add) + }); + + // FIXME: we're in a bit of a pickle here, because we're only saving **one** original value per side, + // but we possibly have multiple original values that changed in the case where the field is an + // array of multiple values that normalize to the same value. + // (e.g. "foo" = ["bar", "Bar", "bAr", "baR"]. I'm not judging why you would do that ¯\_(ツ)_/¯) + // + // We'll work best effort by ignoring when the same value appears in both sides, deleting the first + // value that is only in the old version, and adding the first value that is only in the new version + let mut obkv = KvWriterDelAdd::memory(); + let mut del = None; + let mut add = None; + let mut both = None; + + for eob in merged_strings_iter { + match eob { + EitherOrBoth::Both((_normalized, original), _) => { + both = match both { + Some(both) => Some(both), + None => Some(original), + } + } + EitherOrBoth::Left((_normalized, original)) => { + del = match del { + Some(del) => Some(del), + None => Some(original), + }; + } + EitherOrBoth::Right((_normalized, original)) => { + add = match add { + Some(add) => Some(add), + None => Some(original), + } + } + } + } + + if let Some(del) = del { + obkv.insert(DelAdd::Deletion, del)?; + } + if let Some(add) = add + // prefer the newly added, but if there is none, keep a value in the list of values + // since the normalized value appears both in old and new, we should never remove it. + .or(both) + { + obkv.insert(DelAdd::Addition, add)?; + } + + let truncated = truncate_string(normalized.clone()); key_buffer.extend_from_slice(truncated.as_bytes()); - let mut obkv = KvWriterDelAdd::memory(); - obkv.insert(DelAdd::Deletion, original)?; let bytes = obkv.into_inner()?; fid_docid_facet_strings_sorter.insert(&key_buffer, bytes)?; + continue; } - EitherOrBoth::Right((normalized, original)) => { - let truncated = truncate_string(normalized); - key_buffer.extend_from_slice(truncated.as_bytes()); + EitherOrBoth::Left((_normalized, mut original)) => { + // FIXME: we only consider the first value for the purpose of facet search + // another structure is needed, able to retain all originals associated with a normalized value. + let Some((normalized, original)) = original.next() else { + continue; + }; + (DelAdd::Deletion, normalized, original) + } + EitherOrBoth::Right((_normalized, mut original)) => { + // FIXME: we only consider the first value for the purpose of facet search + // another structure is needed, able to retain all originals associated with a normalized value. + let Some((normalized, original)) = original.next() else { + continue; + }; + (DelAdd::Addition, normalized, original) + } + }; + let truncated = truncate_string(normalized.clone()); + key_buffer.extend_from_slice(truncated.as_bytes()); - let mut obkv = KvWriterDelAdd::memory(); - obkv.insert(DelAdd::Addition, original)?; - let bytes = obkv.into_inner()?; - fid_docid_facet_strings_sorter.insert(&key_buffer, bytes)?; - } - } + let mut obkv = KvWriterDelAdd::memory(); + obkv.insert(side, original)?; + let bytes = obkv.into_inner()?; + fid_docid_facet_strings_sorter.insert(&key_buffer, bytes)?; } Ok(()) From c3cdc407eceea3645d3931ab3a5abaddbd983242 Mon Sep 17 00:00:00 2001 From: Louis Dureuil Date: Thu, 8 Aug 2024 14:57:02 +0200 Subject: [PATCH 22/26] Avoid unnecessary clone() --- .../extract/extract_fid_docid_facet_values.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs b/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs index cc9df70de..93c6ab408 100644 --- a/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs +++ b/milli/src/update/index_documents/extract/extract_fid_docid_facet_values.rs @@ -317,11 +317,15 @@ fn deladd_obkv_cbo_roaring_bitmaps( } /// Truncates a string to the biggest valid LMDB key size. -fn truncate_string(s: String) -> String { - s.char_indices() - .take_while(|(idx, _)| idx + 4 < MAX_FACET_VALUE_LENGTH) - .map(|(_, c)| c) - .collect() +fn truncate_str(s: &str) -> &str { + let index = s + .char_indices() + .map(|(idx, _)| idx) + .chain(std::iter::once(s.len())) + .take_while(|idx| idx <= &MAX_FACET_VALUE_LENGTH) + .last(); + + &s[..index.unwrap_or(0)] } /// Computes the diff between both Del and Add numbers and @@ -466,7 +470,7 @@ where obkv.insert(DelAdd::Addition, add)?; } - let truncated = truncate_string(normalized.clone()); + let truncated = truncate_str(normalized); key_buffer.extend_from_slice(truncated.as_bytes()); let bytes = obkv.into_inner()?; @@ -490,7 +494,7 @@ where (DelAdd::Addition, normalized, original) } }; - let truncated = truncate_string(normalized.clone()); + let truncated = truncate_str(normalized); key_buffer.extend_from_slice(truncated.as_bytes()); let mut obkv = KvWriterDelAdd::memory(); From ade54493aba062de21bebc79d6607e026775d655 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Wed, 14 Aug 2024 11:33:17 +0200 Subject: [PATCH 23/26] Only detect language for a facet if several locales have been specified by the user in the settings --- meilisearch/src/search/mod.rs | 14 ++++++++++---- milli/src/search/facet/search.rs | 10 +++++++++- .../extract/extract_facet_string_docids.rs | 9 +++++++-- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/meilisearch/src/search/mod.rs b/meilisearch/src/search/mod.rs index dada9159b..915505be0 100644 --- a/meilisearch/src/search/mod.rs +++ b/meilisearch/src/search/mod.rs @@ -1369,12 +1369,18 @@ pub fn perform_facet_search( None => TimeBudget::default(), }; + // In the faceted search context, we want to use the intersection between the locales provided by the user + // and the locales of the facet string. + // If the facet string is not localized, we **ignore** the locales provided by the user because the facet data has no locale. + // If the user does not provide locales, we use the locales of the facet string. let localized_attributes = index.localized_attributes_rules(&rtxn)?.unwrap_or_default(); - let locales = locales.or_else(|| { - localized_attributes + let localized_attributes_locales = + localized_attributes.into_iter().find(|attr| attr.match_str(&facet_name)); + let locales = localized_attributes_locales.map(|attr| { + attr.locales .into_iter() - .find(|attr| attr.match_str(&facet_name)) - .map(|attr| attr.locales) + .filter(|locale| locales.as_ref().map_or(true, |locales| locales.contains(locale))) + .collect() }); let (search, _, _, _) = diff --git a/milli/src/search/facet/search.rs b/milli/src/search/facet/search.rs index 39fb7374a..cdba7ee16 100644 --- a/milli/src/search/facet/search.rs +++ b/milli/src/search/facet/search.rs @@ -339,10 +339,18 @@ impl ValuesCollection { fn normalize_facet_string(facet_string: &str, locales: Option<&[Language]>) -> String { let options = NormalizerOption { lossy: true, ..Default::default() }; let mut detection = StrDetection::new(facet_string, locales); + + // Detect the language of the facet string only if several locales are explicitly provided. + let language = match locales { + Some(&[language]) => Some(language), + Some(multiple_locales) if multiple_locales.len() > 1 => detection.language(), + _ => None, + }; + let token = Token { lemma: std::borrow::Cow::Borrowed(facet_string), script: detection.script(), - language: detection.language(), + language, ..Default::default() }; diff --git a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs index 45a7696ac..69663bb08 100644 --- a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs +++ b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs @@ -271,7 +271,7 @@ fn extract_facet_string_docids_settings( /// Normalizes the facet string and truncates it to the max length. #[tracing::instrument(level = "trace", skip_all, target = "indexing::extract")] fn normalize_facet_string(facet_string: &str, locales: Option<&[Language]>) -> String { - let options = NormalizerOption { lossy: true, ..Default::default() }; + let options: NormalizerOption = NormalizerOption { lossy: true, ..Default::default() }; let mut detection = StrDetection::new(facet_string, locales); let script = { @@ -285,7 +285,12 @@ fn normalize_facet_string(facet_string: &str, locales: Option<&[Language]>) -> S let span = tracing::trace_span!(target: "indexing::extract::extract_facet_string_docids", "detect_language"); let _entered = span.enter(); - detection.language() + // Detect the language of the facet string only if several locales are explicitly provided. + match locales { + Some(&[language]) => Some(language), + Some(multiple_locales) if multiple_locales.len() > 1 => detection.language(), + _ => None, + } }; let token = Token { From 0f965d35747226e0fc7bf6056a491f4fea3fd48f Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Wed, 14 Aug 2024 14:33:36 +0200 Subject: [PATCH 24/26] Remove hotloop's spans --- .../extract/extract_facet_string_docids.rs | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs index 69663bb08..36dd20b15 100644 --- a/milli/src/update/index_documents/extract/extract_facet_string_docids.rs +++ b/milli/src/update/index_documents/extract/extract_facet_string_docids.rs @@ -269,28 +269,16 @@ fn extract_facet_string_docids_settings( } /// Normalizes the facet string and truncates it to the max length. -#[tracing::instrument(level = "trace", skip_all, target = "indexing::extract")] fn normalize_facet_string(facet_string: &str, locales: Option<&[Language]>) -> String { let options: NormalizerOption = NormalizerOption { lossy: true, ..Default::default() }; let mut detection = StrDetection::new(facet_string, locales); - let script = { - let span = tracing::trace_span!(target: "indexing::extract::extract_facet_string_docids", "detect_script"); - let _entered = span.enter(); - - detection.script() - }; - - let language = { - let span = tracing::trace_span!(target: "indexing::extract::extract_facet_string_docids", "detect_language"); - let _entered = span.enter(); - - // Detect the language of the facet string only if several locales are explicitly provided. - match locales { - Some(&[language]) => Some(language), - Some(multiple_locales) if multiple_locales.len() > 1 => detection.language(), - _ => None, - } + let script = detection.script(); + // Detect the language of the facet string only if several locales are explicitly provided. + let language = match locales { + Some(&[language]) => Some(language), + Some(multiple_locales) if multiple_locales.len() > 1 => detection.language(), + _ => None, }; let token = Token { @@ -300,10 +288,6 @@ fn normalize_facet_string(facet_string: &str, locales: Option<&[Language]>) -> S ..Default::default() }; - let span = - tracing::trace_span!(target: "indexing::extract::extract_facet_string_docids", "normalize"); - let _entered = span.enter(); - // truncate the facet string to the max length token .normalize(&options) From 8bf89ec394e60b35e75637a73ce0be718789f0c7 Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Wed, 21 Aug 2024 10:47:40 +0200 Subject: [PATCH 25/26] Infer locales from index settings --- meilisearch/tests/search/locales.rs | 331 +++++++++++++++++++++++- milli/src/localized_attributes_rules.rs | 15 ++ milli/src/search/new/mod.rs | 42 ++- 3 files changed, 381 insertions(+), 7 deletions(-) diff --git a/meilisearch/tests/search/locales.rs b/meilisearch/tests/search/locales.rs index 9f1c22b75..dbc4fcc30 100644 --- a/meilisearch/tests/search/locales.rs +++ b/meilisearch/tests/search/locales.rs @@ -386,12 +386,39 @@ async fn force_locales() { |response, code| { snapshot!(response, @r###" { - "hits": [], + "hits": [ + { + "name_zh": "进击的巨人", + "author_zh": "諫山創", + "description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。", + "id": 853, + "_vectors": { + "manual": [ + 1.0, + 2.0, + 3.0 + ] + }, + "_formatted": { + "name_zh": "巨人", + "author_zh": "諫山創", + "description_zh": "巨人是日本的漫画系列,由諫山 創作画。", + "id": "853", + "_vectors": { + "manual": [ + "1.0", + "2.0", + "3.0" + ] + } + } + } + ], "query": "\"进击的巨人\"", "processingTimeMs": "[duration]", "limit": 20, "offset": 0, - "estimatedTotalHits": 0 + "estimatedTotalHits": 1 } "###); snapshot!(code, @"200 OK"); @@ -483,12 +510,39 @@ async fn force_locales_with_pattern() { |response, code| { snapshot!(response, @r###" { - "hits": [], + "hits": [ + { + "name_zh": "进击的巨人", + "author_zh": "諫山創", + "description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。", + "id": 853, + "_vectors": { + "manual": [ + 1.0, + 2.0, + 3.0 + ] + }, + "_formatted": { + "name_zh": "巨人", + "author_zh": "諫山創", + "description_zh": "巨人是日本的漫画系列,由諫山 創作画。", + "id": "853", + "_vectors": { + "manual": [ + "1.0", + "2.0", + "3.0" + ] + } + } + } + ], "query": "\"进击的巨人\"", "processingTimeMs": "[duration]", "limit": 20, "offset": 0, - "estimatedTotalHits": 0 + "estimatedTotalHits": 1 } "###); snapshot!(code, @"200 OK"); @@ -761,6 +815,275 @@ async fn force_different_locales_with_pattern() { .await; } +#[actix_rt::test] +async fn auto_infer_locales_at_search_with_attributes_to_search_on() { + let server = Server::new().await; + + let index = server.index("test"); + let documents = DOCUMENTS.clone(); + let (response, _) = index + .update_settings( + json!({ + "searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"], + "localizedAttributes": [ + // force japanese + {"attributePatterns": ["*_zh"], "locales": ["jpn"]}, + // force chinese + {"attributePatterns": ["*_ja"], "locales": ["cmn"]}, + // any language + {"attributePatterns": ["*_en"], "locales": []} + ] + }), + ) + .await; + snapshot!(response, @r###" + { + "taskUid": 0, + "indexUid": "test", + "status": "enqueued", + "type": "settingsUpdate", + "enqueuedAt": "[date]" + } + "###); + index.add_documents(documents, None).await; + index.wait_task(1).await; + + // auto infer any language + index + .search( + json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}), + |response, code| { + snapshot!(response, @r###" + { + "hits": [], + "query": "\"进击的巨人\"", + "processingTimeMs": "[duration]", + "limit": 20, + "offset": 0, + "estimatedTotalHits": 0 + } + "###); + snapshot!(code, @"200 OK"); + }, + ) + .await; + + // should infer chinese + index + .search( + json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"], "attributesToSearchOn": ["name_zh", "description_zh"]}), + |response, code| { + snapshot!(response, @r###" + { + "hits": [ + { + "name_zh": "进击的巨人", + "author_zh": "諫山創", + "description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。", + "id": 853, + "_vectors": { + "manual": [ + 1.0, + 2.0, + 3.0 + ] + }, + "_formatted": { + "name_zh": "巨人", + "author_zh": "諫山創", + "description_zh": "巨人是日本的漫画系列,由諫山 創作画。", + "id": "853", + "_vectors": { + "manual": [ + "1.0", + "2.0", + "3.0" + ] + } + } + } + ], + "query": "\"进击的巨人\"", + "processingTimeMs": "[duration]", + "limit": 20, + "offset": 0, + "estimatedTotalHits": 1 + } + "###); + snapshot!(code, @"200 OK"); + }, + ) + .await; +} + +#[actix_rt::test] +async fn auto_infer_locales_at_search() { + let server = Server::new().await; + + let index = server.index("test"); + let documents = DOCUMENTS.clone(); + let (response, _) = index + .update_settings( + json!({ + "searchableAttributes": ["name_en", "name_ja", "name_zh", "author_en", "author_ja", "author_zh", "description_en", "description_ja", "description_zh"], + "localizedAttributes": [ + // force japanese + {"attributePatterns": ["*"], "locales": ["jpn"]}, + ] + }), + ) + .await; + snapshot!(response, @r###" + { + "taskUid": 0, + "indexUid": "test", + "status": "enqueued", + "type": "settingsUpdate", + "enqueuedAt": "[date]" + } + "###); + index.add_documents(documents, None).await; + index.wait_task(1).await; + + index + .search( + json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}), + |response, code| { + snapshot!(response, @r###" + { + "hits": [ + { + "name_zh": "进击的巨人", + "author_zh": "諫山創", + "description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。", + "id": 853, + "_vectors": { + "manual": [ + 1.0, + 2.0, + 3.0 + ] + }, + "_formatted": { + "name_zh": "巨人", + "author_zh": "諫山創", + "description_zh": "巨人是日本的漫画系列,由諫山 創作画。", + "id": "853", + "_vectors": { + "manual": [ + "1.0", + "2.0", + "3.0" + ] + } + } + } + ], + "query": "\"进击的巨人\"", + "processingTimeMs": "[duration]", + "limit": 20, + "offset": 0, + "estimatedTotalHits": 1 + } + "###); + snapshot!(code, @"200 OK"); + }, + ) + .await; + + index + .search( + json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}), + |response, code| { + snapshot!(response, @r###" + { + "hits": [ + { + "name_zh": "进击的巨人", + "author_zh": "諫山創", + "description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。", + "id": 853, + "_vectors": { + "manual": [ + 1.0, + 2.0, + 3.0 + ] + }, + "_formatted": { + "name_zh": "巨人", + "author_zh": "諫山創", + "description_zh": "巨人是日本的漫画系列,由諫山 創作画。", + "id": "853", + "_vectors": { + "manual": [ + "1.0", + "2.0", + "3.0" + ] + } + } + } + ], + "query": "\"进击的巨人\"", + "processingTimeMs": "[duration]", + "limit": 20, + "offset": 0, + "estimatedTotalHits": 1 + } + "###); + snapshot!(code, @"200 OK"); + }, + ) + .await; + + index + .search( + json!({"q": "\"进击的巨人\"", "attributesToHighlight": ["*"]}), + |response, code| { + snapshot!(response, @r###" + { + "hits": [ + { + "name_zh": "进击的巨人", + "author_zh": "諫山創", + "description_zh": "进击的巨人是日本的漫画系列,由諫山 創作画。", + "id": 853, + "_vectors": { + "manual": [ + 1.0, + 2.0, + 3.0 + ] + }, + "_formatted": { + "name_zh": "巨人", + "author_zh": "諫山創", + "description_zh": "巨人是日本的漫画系列,由諫山 創作画。", + "id": "853", + "_vectors": { + "manual": [ + "1.0", + "2.0", + "3.0" + ] + } + } + } + ], + "query": "\"进击的巨人\"", + "processingTimeMs": "[duration]", + "limit": 20, + "offset": 0, + "estimatedTotalHits": 1 + } + "###); + snapshot!(code, @"200 OK"); + }, + ) + .await; +} + #[actix_rt::test] async fn force_different_locales_with_pattern_nested() { let server = Server::new().await; diff --git a/milli/src/localized_attributes_rules.rs b/milli/src/localized_attributes_rules.rs index 739d03043..3c421ca6b 100644 --- a/milli/src/localized_attributes_rules.rs +++ b/milli/src/localized_attributes_rules.rs @@ -90,6 +90,21 @@ impl LocalizedFieldIds { pub fn locales(&self, fields_id: FieldId) -> Option<&[Language]> { self.field_id_to_locales.get(&fields_id).map(Vec::as_slice) } + + pub fn all_locales(&self) -> Vec { + let mut locales = Vec::new(); + for field_locales in self.field_id_to_locales.values() { + if !field_locales.is_empty() { + locales.extend(field_locales); + } else { + // If a field has no locales, we consider it as not localized + return Vec::new(); + } + } + locales.sort(); + locales.dedup(); + locales + } } #[cfg(test)] diff --git a/milli/src/search/new/mod.rs b/milli/src/search/new/mod.rs index 577e12a39..b30306a0b 100644 --- a/milli/src/search/new/mod.rs +++ b/milli/src/search/new/mod.rs @@ -49,6 +49,7 @@ pub use self::geo_sort::Strategy as GeoSortStrategy; use self::graph_based_ranking_rule::Words; use self::interner::Interned; use self::vector_sort::VectorSort; +use crate::localized_attributes_rules::LocalizedFieldIds; use crate::score_details::{ScoreDetails, ScoringStrategy}; use crate::search::new::distinct::apply_distinct_rule; use crate::vector::Embedder; @@ -671,9 +672,44 @@ pub fn execute_search( tokbuilder.words_dict(dictionary); } - if let Some(locales) = locales { - tokbuilder.allow_list(locales); - } + let db_locales; + match locales { + Some(locales) => { + if !locales.is_empty() { + tokbuilder.allow_list(locales); + } + } + None => { + // If no locales are specified, we use the locales specified in the localized attributes rules + let localized_attributes_rules = ctx.index.localized_attributes_rules(ctx.txn)?; + let fields_ids_map = ctx.index.fields_ids_map(ctx.txn)?; + let searchable_fields = ctx.index.searchable_fields_ids(ctx.txn)?; + + let localized_fields = match &ctx.restricted_fids { + // if AttributeToSearchOn is set, use the restricted list of ids + Some(restricted_fids) => { + let iter = restricted_fids + .exact + .iter() + .chain(restricted_fids.tolerant.iter()) + .map(|(fid, _)| *fid); + + LocalizedFieldIds::new(&localized_attributes_rules, &fields_ids_map, iter) + } + // Otherwise use the full list of ids coming from the index searchable fields + None => LocalizedFieldIds::new( + &localized_attributes_rules, + &fields_ids_map, + searchable_fields.into_iter(), + ), + }; + + db_locales = localized_fields.all_locales(); + if !db_locales.is_empty() { + tokbuilder.allow_list(&db_locales); + } + } + }; let tokenizer = tokbuilder.build(); drop(entered); From b12e997c8ae79f0e98c1bc2ccb942a4de199c95a Mon Sep 17 00:00:00 2001 From: ManyTheFish Date: Wed, 21 Aug 2024 13:22:56 +0200 Subject: [PATCH 26/26] Add pinyin flag --- meilisearch/tests/search/mod.rs | 2 ++ milli/src/search/mod.rs | 1 + milli/src/search/new/tests/mod.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/meilisearch/tests/search/mod.rs b/meilisearch/tests/search/mod.rs index 301ef9aa2..a05b27947 100644 --- a/meilisearch/tests/search/mod.rs +++ b/meilisearch/tests/search/mod.rs @@ -7,6 +7,7 @@ mod facet_search; mod formatted; mod geo; mod hybrid; +#[cfg(not(feature = "chinese-pinyin"))] mod locales; mod matching_strategy; mod multi; @@ -392,6 +393,7 @@ async fn negative_special_cases_search() { } #[cfg(feature = "default")] +#[cfg(not(feature = "chinese-pinyin"))] #[actix_rt::test] async fn test_kanji_language_detection() { let server = Server::new().await; diff --git a/milli/src/search/mod.rs b/milli/src/search/mod.rs index 0f5eb23e1..3057066d2 100644 --- a/milli/src/search/mod.rs +++ b/milli/src/search/mod.rs @@ -360,6 +360,7 @@ mod test { use super::*; #[cfg(feature = "japanese")] + #[cfg(not(feature = "chinese-pinyin"))] #[test] fn test_kanji_language_detection() { use crate::index::tests::TempIndex; diff --git a/milli/src/search/new/tests/mod.rs b/milli/src/search/new/tests/mod.rs index 0faff9425..37bca7597 100644 --- a/milli/src/search/new/tests/mod.rs +++ b/milli/src/search/new/tests/mod.rs @@ -6,6 +6,7 @@ pub mod exactness; pub mod geo_sort; pub mod integration; #[cfg(feature = "all-tokenizations")] +#[cfg(not(feature = "chinese-pinyin"))] pub mod language; pub mod ngram_split_words; pub mod proximity;