From a68a52ad6771d392fab352157006e0345a08cf45 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 6 Nov 2025 20:49:04 +0100 Subject: [PATCH] feat: can add limit length for a variable --- locale/fr/LC_MESSAGES/rougail.po | 208 +++++++++++------- locale/rougail.pot | 180 ++++++++------- src/rougail/annotator/property.py | 2 +- src/rougail/annotator/variable.py | 37 +++- src/rougail/locale/fr/LC_MESSAGES/rougail.mo | Bin 17158 -> 18431 bytes .../makedict/after.json | 10 + .../makedict/base.json | 4 + .../makedict/before.json | 10 + .../makedict/mandatory.json | 1 + .../makedict/read_write.json | 4 + .../01_6string_multi_length/tiramisu/base.py | 19 ++ .../tiramisu/no_namespace.py | 14 ++ tests/test_1_flattener.py | 2 +- tests/test_2_makedict.py | 2 +- 14 files changed, 338 insertions(+), 155 deletions(-) create mode 100644 tests/dictionaries/01_6string_multi_length/makedict/after.json create mode 100644 tests/dictionaries/01_6string_multi_length/makedict/base.json create mode 100644 tests/dictionaries/01_6string_multi_length/makedict/before.json create mode 100644 tests/dictionaries/01_6string_multi_length/makedict/mandatory.json create mode 100644 tests/dictionaries/01_6string_multi_length/makedict/read_write.json create mode 100644 tests/dictionaries/01_6string_multi_length/tiramisu/base.py create mode 100644 tests/dictionaries/01_6string_multi_length/tiramisu/no_namespace.py diff --git a/locale/fr/LC_MESSAGES/rougail.po b/locale/fr/LC_MESSAGES/rougail.po index 982500bf5..8f9eb9bb8 100644 --- a/locale/fr/LC_MESSAGES/rougail.po +++ b/locale/fr/LC_MESSAGES/rougail.po @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2025-10-26 15:26+0100\n" -"PO-Revision-Date: 2025-10-26 15:28+0100\n" +"POT-Creation-Date: 2025-11-06 21:31+0100\n" +"PO-Revision-Date: 2025-11-06 21:32+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -86,10 +86,8 @@ msgstr "" "nom de l'étiquette invalide \"{0}\" ne doit pas être un nom de mode existant" #: src/rougail/annotator/property.py:168 -#, fuzzy -#| msgid "" -#| "invalid tag name \"{0}\" should not be name of an available proprerties" -msgid "invalid tag name \"{0}\" should not be name of an available properties" +msgid "" +"invalid tag name \"{0}\" should not be the name of an available properties" msgstr "" "nom de l'étiquette invalide \"{0}\" ne doit pas être le nom d'une propriétés " "existantes" @@ -139,97 +137,127 @@ msgstr "" "la variable \"{0}\" a l'attribut \"secret_manager\" donc ne devrait pas " "avoir de valeur par défaut" -#: src/rougail/annotator/variable.py:254 +#: src/rougail/annotator/variable.py:154 +msgid "{0} values needed, but there are {{{{ var | length }}}}" +msgstr "il faut {0} valeurs, mais il y en a {{{{ var | length }}}}" + +#: src/rougail/annotator/variable.py:155 +msgid "needs exactly {0} values" +msgstr "nécessite exactement {0} valeurs" + +#: src/rougail/annotator/variable.py:157 +msgid "" +"a maximum of {0} values are needed, but there are {{{{ var | length }}}}" +msgstr "il faut au maximum {0} valeurs, mais il y en a {{{{ var | length }}}}" + +#: src/rougail/annotator/variable.py:158 +msgid "needs a maximum of {0} values" +msgstr "nécessite au maximum {0} valeurs" + +#: src/rougail/annotator/variable.py:160 +msgid "" +"a minimum of {0} values are needed, but there are {{{{ var | length }}}}" +msgstr "il faut au minimum {0} valeurs, mais il y en a {{{{ var | length }}}}" + +#: src/rougail/annotator/variable.py:161 +msgid "needs a minimum of {0} values" +msgstr "nécessite au minimum {0} valeurs" + +#: src/rougail/annotator/variable.py:223 +msgid "the \"{0}\" default value is a calculation with itself" +msgstr "la valeur par défaut \"{0}\" est un calcul avec elle-même" + +#: src/rougail/annotator/variable.py:285 msgid "" "the variable \"{0}\" has regexp attribut but has not the \"regexp\" type" msgstr "" "la variable \"{0}\" a un attribut regexp mais n'a pas le type \"regexp\"" -#: src/rougail/annotator/variable.py:297 +#: src/rougail/annotator/variable.py:328 msgid "" "the variable \"{0}\" has choices attribut but has not the \"choice\" type" msgstr "" "la variable \"{0}\" a un attribut choices mais n'a pas le type \"choice\"" -#: src/rougail/annotator/variable.py:325 +#: src/rougail/annotator/variable.py:356 msgid "" "the variable \"{0}\" has an unvalid default value \"{1}\" should be in {2}" msgstr "" "la variable \"{0}\" a la valeur par défaut invalide \"{1}\" devrait être {2}" -#: src/rougail/config/__init__.py:235 +#: src/rougail/config/__init__.py:276 msgid "Structure format version by default, if not specified in structure file" msgstr "" "La version du format de la structure par défaut, si non spécifier dans le " "fichier de structure" -#: src/rougail/config/__init__.py:243 +#: src/rougail/config/__init__.py:284 msgid "File with functions" msgstr "Fichier avec les fonctions" -#: src/rougail/config/__init__.py:255 +#: src/rougail/config/__init__.py:296 msgid "All modes level available" msgstr "Tous les niveaux de modes valides" -#: src/rougail/config/__init__.py:267 +#: src/rougail/config/__init__.py:308 msgid "Default mode for a family" msgstr "Mode par défaut pour une famille" -#: src/rougail/config/__init__.py:287 +#: src/rougail/config/__init__.py:328 msgid "Default mode for a variable" msgstr "Mode par défaut pour une variable" -#: src/rougail/config/__init__.py:311 +#: src/rougail/config/__init__.py:352 msgid "Option name for the base option" msgstr "Nom de l'option pour l'option de base" -#: src/rougail/config/__init__.py:316 +#: src/rougail/config/__init__.py:357 msgid "In cache file, do not importation of Tiramisu and other dependencies" msgstr "" "Dans le fichier de cache, ne pas importer Tiramisu et autres dépendances" -#: src/rougail/config/__init__.py:321 +#: src/rougail/config/__init__.py:362 msgid "Tiramisu cache filename" msgstr "Nom du fichier du cache Tiramisu" -#: src/rougail/config/__init__.py:329 +#: src/rougail/config/__init__.py:370 msgid "Name of internal functions that we can use as a function" msgstr "" "Nom des fonctions internes qu'il est possible d'utiliser comme fonction" -#: src/rougail/config/__init__.py:335 +#: src/rougail/config/__init__.py:376 msgid "Name of extra annotators" msgstr "Nom des annotators supplémentaires" -#: src/rougail/config/__init__.py:341 +#: src/rougail/config/__init__.py:382 msgid "Suffix add to generated options name" msgstr "Suffix ajouté pour généré le nom des options" -#: src/rougail/config/__init__.py:347 +#: src/rougail/config/__init__.py:388 msgid "Every variables in calculation are optionals" msgstr "Toutes les variables dans un calcul sont optionnelles" -#: src/rougail/config/__init__.py:351 +#: src/rougail/config/__init__.py:392 msgid "Loads redefine variables even if there don't already exists" msgstr "Charger les variables redéfinis même si elles n'existe pas" -#: src/rougail/config/__init__.py:358 +#: src/rougail/config/__init__.py:399 msgid "The secret pattern to build item name in Bitwarden" msgstr "Le patron de secret pour construire le nom de l'élément dans Bitwarden" -#: src/rougail/config/__init__.py:359 +#: src/rougail/config/__init__.py:400 msgid "The pattern is in Jinja format" msgstr "Le patron est au format Jinja" -#: src/rougail/config/__init__.py:387 +#: src/rougail/config/__init__.py:428 msgid "Select for {0}" msgstr "Sélection pour {0}" -#: src/rougail/config/__init__.py:467 +#: src/rougail/config/__init__.py:508 msgid "Override default parameters for option type" msgstr "Sur charger les paramètre par défaut pour le type d'option" -#: src/rougail/config/__init__.py:470 +#: src/rougail/config/__init__.py:511 msgid "Default parameters for option type" msgstr "Paramètre par défaut pour le type d'option" @@ -268,42 +296,42 @@ msgstr "" "définition invalide pour la définition des \"structures\" ({0}), aucun " "fichier de structure ne peut être chargé !" -#: src/rougail/convert/object_model.py:122 +#: src/rougail/convert/object_model.py:121 msgid "cannot find variable \"{0}\" defined in attribute \"{1}\" for \"{2}\"" msgstr "" "ne peut trouver la variable \"{0}\" défini dans l'attribut \"{1}\" pour " "\"{2}\"" -#: src/rougail/convert/object_model.py:128 +#: src/rougail/convert/object_model.py:127 msgid "" "the variable \"{0}\" is in fact a family in attribute \"{1}\" for \"{2}\"" msgstr "" "la variable \"{0}\" est en faite une famille dans l'attribut \"{1}\" pour " "\"{2}\"" -#: src/rougail/convert/object_model.py:133 -#: src/rougail/convert/object_model.py:479 +#: src/rougail/convert/object_model.py:132 +#: src/rougail/convert/object_model.py:484 msgid "unknown object \"{0}\" in attribute \"{1}\" for \"{2}\"" msgstr "objet inconnu \"{0}\" dans l'attribut \"{1}\" pour \"{2}\"" -#: src/rougail/convert/object_model.py:152 +#: src/rougail/convert/object_model.py:151 msgid "" "identifier parameter for \"{0}\" in \"{1}\" cannot be set none dynamic family" msgstr "" "le paramètre identifier pour \"{0}\" dans \"{1}\" ne peut être placé pour " "une famille non dynamique" -#: src/rougail/convert/object_model.py:181 +#: src/rougail/convert/object_model.py:180 msgid "cannot find variable \"{0}\" defined in \"{1}\" for \"{2}\"" msgstr "ne peut trouver la variable \"{0}\" défini dans \"{1}\" pour \"{2}\"" -#: src/rougail/convert/object_model.py:186 +#: src/rougail/convert/object_model.py:185 msgid "variable \"{0}\" defined in \"{1}\" for \"{2}\" is a dynamic variable" msgstr "" "la variable \"{0}\" défini dans \"{1}\" pour \"{2}\" est une variable " "dynamique" -#: src/rougail/convert/object_model.py:203 +#: src/rougail/convert/object_model.py:202 msgid "" "the variable \"{0}\" is not a follower, so cannot have index type for param " "in \"{1}\"" @@ -311,7 +339,15 @@ msgstr "" "la variable \"{0}\" n'est pas suiveuse, donc ne peut avoir de type index " "comme paramètre dans \"{1}\"" -#: src/rougail/convert/object_model.py:405 +#: src/rougail/convert/object_model.py:252 +msgid "" +"\"warnings\" are only available with attribute \"{self.attribute_name}\" for " +"variable \"{self.ori_path}\"" +msgstr "" +"\"warnings\" est seulement utilisable avec l'attribut \"{self.attribute_name}" +"\" pour la variable \"{self.ori_path}\"" + +#: src/rougail/convert/object_model.py:410 msgid "" "variable \"{0}\" has a calculating \"{1}\" with an invalid return_type, " "should be boolean or string, not \"{2}\"" @@ -319,7 +355,7 @@ msgstr "" "la variable \"{0}\" a un calcul \"{1}\" avec un return_type invalide, " "devrait être un booléen ou une chaîne de caractère, et pas \"{2}\"" -#: src/rougail/convert/object_model.py:474 +#: src/rougail/convert/object_model.py:479 msgid "" "a variable \"{0}\" is needs in attribute \"{1}\" for \"{2}\" but it's a " "family" @@ -327,7 +363,7 @@ msgstr "" "une variable \"{0}\" est nécessaire pour l'attribut \"{1}\" pour \"{2}\" " "mais c'est une famille" -#: src/rougail/convert/object_model.py:499 +#: src/rougail/convert/object_model.py:504 msgid "" "variable \"{0}\" has an attribute \"{1}\" calculated with the unknown " "variable \"{2}\"" @@ -335,7 +371,7 @@ msgstr "" "la variable \"{0}\" a un attribut invalide \"{1}\" calculé avec la variable " "inconnue \"{2}\"" -#: src/rougail/convert/object_model.py:551 +#: src/rougail/convert/object_model.py:556 msgid "" "the variable \"{0}\" has an invalid \"{1}\" the variable \"{2}\" is in a sub " "dynamic option" @@ -343,14 +379,14 @@ msgstr "" "la variable \"{0}\" a un attribut invalide \"{1}\", la variable \"{2}\" est " "dans une sous option dynamique" -#: src/rougail/convert/object_model.py:560 +#: src/rougail/convert/object_model.py:565 msgid "" "the leader \"{0}\" has an invalid \"{1}\" the follower \"{2}\" is a multi" msgstr "" "la variable meneuse \"{0}\" a un attribut invalide \"{1}\", la variable " "suiveuse \"{2}\" est multiple" -#: src/rougail/convert/object_model.py:602 +#: src/rougail/convert/object_model.py:607 msgid "" "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" " "must not be multi" @@ -358,7 +394,7 @@ msgstr "" "la variable \"{0}\" a un attribut invalide \"{1}\", la variable \"{2}\" ne " "doit pas être multiple" -#: src/rougail/convert/object_model.py:616 +#: src/rougail/convert/object_model.py:621 msgid "" "the variable \"{0}\" has an invalid attribute \"{1}\", the variable must not " "be a multi or the variable \"{2}\" must be multi" @@ -366,7 +402,7 @@ msgstr "" "la variable \"{0}\" a un attribut invalide \"{1}\", la variable ne doit pas " "être multiple ou la variable \"{2}\" doit être multiple" -#: src/rougail/convert/object_model.py:630 +#: src/rougail/convert/object_model.py:635 msgid "" "the variable \"{0}\" has an invalid attribute \"{1}\", the variable must be " "a multi or the variable \"{2}\" must not be multi" @@ -374,7 +410,7 @@ msgstr "" "la variable \"{0}\" a un attribut invalide \"{1}\", la variable doit être " "multiple ou la variable \"{2}\" ne doit pas être multiple" -#: src/rougail/convert/object_model.py:644 +#: src/rougail/convert/object_model.py:649 msgid "" "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" " "is multi but is inside a list" @@ -382,7 +418,7 @@ msgstr "" "la variable \"{0}\" a un attribut invalide \"{1}\", la variable \"{2}\" est " "multiple mais est dans une liste" -#: src/rougail/convert/object_model.py:666 +#: src/rougail/convert/object_model.py:671 msgid "" "the variable \"{0}\" is waiting for a list as \"{1}\" but the attribute " "\"default\" is not a list (\"{2}\")" @@ -390,7 +426,7 @@ msgstr "" "la variable \"{0}\" attend une liste comme \"{1}\" mais l'attribut " "\"default\" n'est pas une liste \"{2}\"" -#: src/rougail/convert/object_model.py:668 +#: src/rougail/convert/object_model.py:673 msgid "" "the variable \"{0}\" is not waiting for a list as \"{1}\" but the attribute " "\"default\" is a list (\"{2}\")" @@ -398,7 +434,7 @@ msgstr "" "la variable \"{0}\" n'attend pas une liste comme \"{1}\" mais l'attribut " "\"default\" est une liste \"{2}\"" -#: src/rougail/convert/object_model.py:684 +#: src/rougail/convert/object_model.py:689 msgid "" "\"{0}\" attribut shall not have an \"optional\" attribute without the " "\"default\" attribute for variable \"{1}\"" @@ -406,7 +442,7 @@ msgstr "" "l'attribut \"{0}\" ne devrait pas avoir d'attribut \"optional\" sans " "l'attribut \"default\" pour la variable \"{1}\"" -#: src/rougail/convert/object_model.py:708 +#: src/rougail/convert/object_model.py:713 msgid "" "variable \"{0}\" has a default value calculated with \"{1}\" which has " "incompatible type" @@ -414,7 +450,7 @@ msgstr "" "la variable \"{0}\" a une valeur par défaut calculé a partir de \"{1}\" " "laquelle a un type incompatible" -#: src/rougail/convert/object_model.py:751 +#: src/rougail/convert/object_model.py:756 msgid "" "the variable \"{0}\" is waiting for a boolean as \"{1}\" but the attribute " "\"default\" is not a boolean (\"{2}\")" @@ -422,7 +458,7 @@ msgstr "" "la variable \"{0}\" attend un booléan comme \"{1}\" mais l'attribut " "\"default\" n'est pas une booléan (\"{2}\")" -#: src/rougail/convert/object_model.py:771 +#: src/rougail/convert/object_model.py:776 msgid "" "\"when\" is not allowed in format version 1.0 for attribute \"{0}\" for " "variable \"{1}\"" @@ -430,7 +466,7 @@ msgstr "" "\"when\" n'est pas autorisé avec le format en version 1.0 pour l'attribut " "\"{0}\" pour la variable \"{1}\"" -#: src/rougail/convert/object_model.py:776 +#: src/rougail/convert/object_model.py:781 msgid "" "the variable \"{0}\" has an invalid attribute \"{1}\", \"when\" and " "\"when_not\" cannot set together" @@ -438,7 +474,7 @@ msgstr "" "la variable \"{0}\" a un attribut invalide \"{1}\", \"when\" et \"when_not\" " "ne peuvent pas être défini ensemble" -#: src/rougail/convert/object_model.py:784 +#: src/rougail/convert/object_model.py:789 msgid "" "\"when_not\" is not allowed in format version 1.0 for attribute \"{0}\" for " "variable \"{1}\"" @@ -446,7 +482,7 @@ msgstr "" "\"when_not\" n'est pas autorisé au format 1.0 pour l'attribut \"{0}\" pour " "la variable variable \"{1}\"" -#: src/rougail/convert/object_model.py:840 +#: src/rougail/convert/object_model.py:845 msgid "" "cannot find variable \"{0}\" for the information \"{1}\" when calculating " "\"{2}\"" @@ -454,19 +490,19 @@ msgstr "" "ne peut trouver la variable \"{0}\" pour l'information \"{1}\" lors du " "calcul de \"{2}\"" -#: src/rougail/convert/object_model.py:845 +#: src/rougail/convert/object_model.py:850 msgid "" "identifier not allowed for the information \"{0}\" when calculating \"{1}\"" msgstr "" "identifier n'est pas autorisé pour l'information \"{0}\" lors du calcul de " "\"{1}\"" -#: src/rougail/convert/object_model.py:897 +#: src/rougail/convert/object_model.py:902 msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\"" msgstr "\"when\" n'est pas autorisé au format 1.0 pour l'attribut \"{0}\"" -#: src/rougail/convert/object_model.py:903 -#: src/rougail/convert/object_model.py:913 +#: src/rougail/convert/object_model.py:908 +#: src/rougail/convert/object_model.py:918 msgid "" "the identifier has an invalid attribute \"{0}\", \"when\" and \"when_not\" " "cannot set together" @@ -474,7 +510,7 @@ msgstr "" "l'identifiant a un attribut invalide \"{0}\", \"when\" et \"when_not\" ne " "peuvent pas être défini ensemble" -#: src/rougail/convert/object_model.py:939 +#: src/rougail/convert/object_model.py:944 msgid "" "the variable \"{0}\" is not a follower, so cannot have index type for \"{1}\"" msgstr "" @@ -494,7 +530,7 @@ msgid "internal error, {0} is not a dynamic variable" msgstr "erreur interne, \"{0}\" n'est pas une variable dynamique" #: src/rougail/error.py:61 src/rougail/tiramisu.py:157 -#: src/rougail/user_datas.py:392 src/rougail/user_datas.py:395 +#: src/rougail/user_datas.py:407 src/rougail/user_datas.py:410 msgid "{0} in {1}" msgstr "{0} dans {1}" @@ -552,24 +588,24 @@ msgstr "" "ne peut calculer l'attribut \"{0}\" pour la variable \"{1}\" dans {2} avec " "les paramètres \"{3}\" : {4}" -#: src/rougail/user_datas.py:135 +#: src/rougail/user_datas.py:145 msgid "" "cannot load variable path \"{0}\", the identifier \"{1}\" is not valid in {2}" msgstr "" "ne peut charger la variable \"{0}\", l'identifiant \"{1}\" n'est pas valide " "dans {2}" -#: src/rougail/user_datas.py:218 +#: src/rougail/user_datas.py:228 msgid "the variable \"{0}\" contains secrets and should not be defined in {1}" msgstr "" "la variable \"{0}\" contient des secrets et ne devrait pas être défini dans " "{1}" -#: src/rougail/user_datas.py:257 +#: src/rougail/user_datas.py:268 msgid "loaded from {0}" msgstr "chargée depuis {0}" -#: src/rougail/user_datas.py:297 +#: src/rougail/user_datas.py:308 msgid "" "cannot set the value \"{0}\" to the family {1}, it will be ignored when " "loading from {2}" @@ -577,7 +613,11 @@ msgstr "" "impossible de définir la valeur \"{0}\" à la famille {1}, elle sera ignorée " "lors du chargement depuis {2}" -#: src/rougail/user_datas.py:309 +#: src/rougail/user_datas.py:319 src/rougail/user_datas.py:336 +msgid "{0} loaded from {1}" +msgstr "{0} chargée depuis {1}" + +#: src/rougail/user_datas.py:324 msgid "" "variable or family \"{0}\" does not exist, it will be ignored when loading " "from {1}" @@ -585,7 +625,7 @@ msgstr "" "la variable ou la famille \"{0}\" n'existe pas, elle sera ignorée lors du " "chargement depuis {1}" -#: src/rougail/user_datas.py:315 +#: src/rougail/user_datas.py:330 msgid "" "\"{0}\" is the name of a dynamic family, it will be ignored when loading " "from {1}" @@ -593,11 +633,7 @@ msgstr "" "\"{0}\" est le nom d'une famille dynamique, il sera ignoré lors du " "chargement depuis {1}" -#: src/rougail/user_datas.py:321 -msgid "{0} loaded from {1}" -msgstr "{0} chargée depuis {1}" - -#: src/rougail/user_datas.py:349 +#: src/rougail/user_datas.py:364 msgid "" "variable {0} at index \"{1}\" is {2}, it will be ignored when loading from " "{3}" @@ -605,23 +641,23 @@ msgstr "" "la variable {0} à l'index \"{1}\" est {2}, elle sera ignorée lors du " "chargement depuis {3}" -#: src/rougail/user_datas.py:360 +#: src/rougail/user_datas.py:375 msgid "" "family {0} is {1}, {2} at index \"{3}\" will be ignored when loading from {4}" msgstr "" "la famille {0} est {1}, {2} à l'index \"{3}\" sera ignorée lors du " "chargement depuis {4}" -#: src/rougail/user_datas.py:373 +#: src/rougail/user_datas.py:388 msgid "variable {0} is {1}, it will be ignored when loading from {2}" msgstr "" "la variable {0} est {1}, elle sera ignorée lors du chargement depuis {2}" -#: src/rougail/user_datas.py:381 +#: src/rougail/user_datas.py:396 msgid "family {0} is {1}, {2} will be ignored when loading from {3}" msgstr "la famille {0} est {1}, {2} sera ignorée lors du chargement depuis {3}" -#: src/rougail/user_datas.py:401 +#: src/rougail/user_datas.py:416 msgid "" "the value \"{0}\" is an invalid {1} for {2} at index \"{3}\", {4}, it will " "be ignored when loading from {5}" @@ -629,7 +665,7 @@ msgstr "" "la valeur \"{0}\" est un invalide {1} pour {2} à l'index \"{3}\", {4}, elle " "sera ignorée lors du chargement depuis {5}" -#: src/rougail/user_datas.py:415 +#: src/rougail/user_datas.py:430 msgid "" "the value \"{0}\" is an invalid {1} for {2}, {3}, it will be ignored when " "loading from {4}" @@ -669,6 +705,28 @@ msgstr "unique" msgid "auto modified" msgstr "auto modifiée" +#, fuzzy +#~| msgid "" +#~| "we need {0} values when there are {{{{ var | length }}}} ({{{{ var | " +#~| "join(\", \")}}}})" +#~ msgid "" +#~ "it needs {0} values maximum when there are {{{{ var | length }}}} " +#~ "({{{{ var | join(\", \")}}}})" +#~ msgstr "" +#~ "we need {0} values when there are {{{{ var | length }}}} ({{{{ var | " +#~ "join(\", \")}}}})" + +#, fuzzy +#~| msgid "" +#~| "we need {0} values when there are {{{{ var | length }}}} ({{{{ var | " +#~| "join(\", \")}}}})" +#~ msgid "" +#~ "it needs {0} values minimum when there are {{{{ var | length }}}} " +#~ "({{{{ var | join(\", \")}}}})" +#~ msgstr "" +#~ "we need {0} values when there are {{{{ var | length }}}} ({{{{ var | " +#~ "join(\", \")}}}})" + #~ msgid "" #~ "the variable \"{0}\" is a family, so cannot set the value \"{1}\" in {2}" #~ msgstr "" diff --git a/locale/rougail.pot b/locale/rougail.pot index df2bb5481..24fc6ad53 100644 --- a/locale/rougail.pot +++ b/locale/rougail.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2025-10-26 15:29+0100\n" +"POT-Creation-Date: 2025-11-06 21:32+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -56,7 +56,7 @@ msgid "invalid tag name \"{0}\" should not be a name of an existing mode" msgstr "" #: src/rougail/annotator/property.py:168 -msgid "invalid tag name \"{0}\" should not be name of an available properties" +msgid "invalid tag name \"{0}\" should not be the name of an available properties" msgstr "" #: src/rougail/annotator/value.py:78 @@ -87,87 +87,115 @@ msgstr "" msgid "the variable \"{0}\" has attribute \"secret_manager\" so must not have default value" msgstr "" -#: src/rougail/annotator/variable.py:254 +#: src/rougail/annotator/variable.py:154 +msgid "{0} values needed, but there are {{{{ var | length }}}}" +msgstr "" + +#: src/rougail/annotator/variable.py:155 +msgid "needs exactly {0} values" +msgstr "" + +#: src/rougail/annotator/variable.py:157 +msgid "a maximum of {0} values are needed, but there are {{{{ var | length }}}}" +msgstr "" + +#: src/rougail/annotator/variable.py:158 +msgid "needs a maximum of {0} values" +msgstr "" + +#: src/rougail/annotator/variable.py:160 +msgid "a minimum of {0} values are needed, but there are {{{{ var | length }}}}" +msgstr "" + +#: src/rougail/annotator/variable.py:161 +msgid "needs a minimum of {0} values" +msgstr "" + +#: src/rougail/annotator/variable.py:223 +msgid "the \"{0}\" default value is a calculation with itself" +msgstr "" + +#: src/rougail/annotator/variable.py:285 msgid "the variable \"{0}\" has regexp attribut but has not the \"regexp\" type" msgstr "" -#: src/rougail/annotator/variable.py:297 +#: src/rougail/annotator/variable.py:328 msgid "the variable \"{0}\" has choices attribut but has not the \"choice\" type" msgstr "" -#: src/rougail/annotator/variable.py:325 +#: src/rougail/annotator/variable.py:356 msgid "the variable \"{0}\" has an unvalid default value \"{1}\" should be in {2}" msgstr "" -#: src/rougail/config/__init__.py:235 +#: src/rougail/config/__init__.py:276 msgid "Structure format version by default, if not specified in structure file" msgstr "" -#: src/rougail/config/__init__.py:243 +#: src/rougail/config/__init__.py:284 msgid "File with functions" msgstr "" -#: src/rougail/config/__init__.py:255 +#: src/rougail/config/__init__.py:296 msgid "All modes level available" msgstr "" -#: src/rougail/config/__init__.py:267 +#: src/rougail/config/__init__.py:308 msgid "Default mode for a family" msgstr "" -#: src/rougail/config/__init__.py:287 +#: src/rougail/config/__init__.py:328 msgid "Default mode for a variable" msgstr "" -#: src/rougail/config/__init__.py:311 +#: src/rougail/config/__init__.py:352 msgid "Option name for the base option" msgstr "" -#: src/rougail/config/__init__.py:316 +#: src/rougail/config/__init__.py:357 msgid "In cache file, do not importation of Tiramisu and other dependencies" msgstr "" -#: src/rougail/config/__init__.py:321 +#: src/rougail/config/__init__.py:362 msgid "Tiramisu cache filename" msgstr "" -#: src/rougail/config/__init__.py:329 +#: src/rougail/config/__init__.py:370 msgid "Name of internal functions that we can use as a function" msgstr "" -#: src/rougail/config/__init__.py:335 +#: src/rougail/config/__init__.py:376 msgid "Name of extra annotators" msgstr "" -#: src/rougail/config/__init__.py:341 +#: src/rougail/config/__init__.py:382 msgid "Suffix add to generated options name" msgstr "" -#: src/rougail/config/__init__.py:347 +#: src/rougail/config/__init__.py:388 msgid "Every variables in calculation are optionals" msgstr "" -#: src/rougail/config/__init__.py:351 +#: src/rougail/config/__init__.py:392 msgid "Loads redefine variables even if there don't already exists" msgstr "" -#: src/rougail/config/__init__.py:358 +#: src/rougail/config/__init__.py:399 msgid "The secret pattern to build item name in Bitwarden" msgstr "" -#: src/rougail/config/__init__.py:359 +#: src/rougail/config/__init__.py:400 msgid "The pattern is in Jinja format" msgstr "" -#: src/rougail/config/__init__.py:387 +#: src/rougail/config/__init__.py:428 msgid "Select for {0}" msgstr "" -#: src/rougail/config/__init__.py:467 +#: src/rougail/config/__init__.py:508 msgid "Override default parameters for option type" msgstr "" -#: src/rougail/config/__init__.py:470 +#: src/rougail/config/__init__.py:511 msgid "Default parameters for option type" msgstr "" @@ -203,121 +231,125 @@ msgstr "" msgid "invalid \"structural\" definition ({0}), we cannot load any structural file!" msgstr "" -#: src/rougail/convert/object_model.py:122 +#: src/rougail/convert/object_model.py:121 msgid "cannot find variable \"{0}\" defined in attribute \"{1}\" for \"{2}\"" msgstr "" -#: src/rougail/convert/object_model.py:128 +#: src/rougail/convert/object_model.py:127 msgid "the variable \"{0}\" is in fact a family in attribute \"{1}\" for \"{2}\"" msgstr "" -#: src/rougail/convert/object_model.py:133 -#: src/rougail/convert/object_model.py:479 +#: src/rougail/convert/object_model.py:132 +#: src/rougail/convert/object_model.py:484 msgid "unknown object \"{0}\" in attribute \"{1}\" for \"{2}\"" msgstr "" -#: src/rougail/convert/object_model.py:152 +#: src/rougail/convert/object_model.py:151 msgid "identifier parameter for \"{0}\" in \"{1}\" cannot be set none dynamic family" msgstr "" -#: src/rougail/convert/object_model.py:181 +#: src/rougail/convert/object_model.py:180 msgid "cannot find variable \"{0}\" defined in \"{1}\" for \"{2}\"" msgstr "" -#: src/rougail/convert/object_model.py:186 +#: src/rougail/convert/object_model.py:185 msgid "variable \"{0}\" defined in \"{1}\" for \"{2}\" is a dynamic variable" msgstr "" -#: src/rougail/convert/object_model.py:203 +#: src/rougail/convert/object_model.py:202 msgid "the variable \"{0}\" is not a follower, so cannot have index type for param in \"{1}\"" msgstr "" -#: src/rougail/convert/object_model.py:405 +#: src/rougail/convert/object_model.py:252 +msgid "\"warnings\" are only available with attribute \"{self.attribute_name}\" for variable \"{self.ori_path}\"" +msgstr "" + +#: src/rougail/convert/object_model.py:410 msgid "variable \"{0}\" has a calculating \"{1}\" with an invalid return_type, should be boolean or string, not \"{2}\"" msgstr "" -#: src/rougail/convert/object_model.py:474 +#: src/rougail/convert/object_model.py:479 msgid "a variable \"{0}\" is needs in attribute \"{1}\" for \"{2}\" but it's a family" msgstr "" -#: src/rougail/convert/object_model.py:499 +#: src/rougail/convert/object_model.py:504 msgid "variable \"{0}\" has an attribute \"{1}\" calculated with the unknown variable \"{2}\"" msgstr "" -#: src/rougail/convert/object_model.py:551 +#: src/rougail/convert/object_model.py:556 msgid "the variable \"{0}\" has an invalid \"{1}\" the variable \"{2}\" is in a sub dynamic option" msgstr "" -#: src/rougail/convert/object_model.py:560 +#: src/rougail/convert/object_model.py:565 msgid "the leader \"{0}\" has an invalid \"{1}\" the follower \"{2}\" is a multi" msgstr "" -#: src/rougail/convert/object_model.py:602 +#: src/rougail/convert/object_model.py:607 msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" must not be multi" msgstr "" -#: src/rougail/convert/object_model.py:616 +#: src/rougail/convert/object_model.py:621 msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable must not be a multi or the variable \"{2}\" must be multi" msgstr "" -#: src/rougail/convert/object_model.py:630 +#: src/rougail/convert/object_model.py:635 msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable must be a multi or the variable \"{2}\" must not be multi" msgstr "" -#: src/rougail/convert/object_model.py:644 +#: src/rougail/convert/object_model.py:649 msgid "the variable \"{0}\" has an invalid attribute \"{1}\", the variable \"{2}\" is multi but is inside a list" msgstr "" -#: src/rougail/convert/object_model.py:666 +#: src/rougail/convert/object_model.py:671 msgid "the variable \"{0}\" is waiting for a list as \"{1}\" but the attribute \"default\" is not a list (\"{2}\")" msgstr "" -#: src/rougail/convert/object_model.py:668 +#: src/rougail/convert/object_model.py:673 msgid "the variable \"{0}\" is not waiting for a list as \"{1}\" but the attribute \"default\" is a list (\"{2}\")" msgstr "" -#: src/rougail/convert/object_model.py:684 +#: src/rougail/convert/object_model.py:689 msgid "\"{0}\" attribut shall not have an \"optional\" attribute without the \"default\" attribute for variable \"{1}\"" msgstr "" -#: src/rougail/convert/object_model.py:708 +#: src/rougail/convert/object_model.py:713 msgid "variable \"{0}\" has a default value calculated with \"{1}\" which has incompatible type" msgstr "" -#: src/rougail/convert/object_model.py:751 +#: src/rougail/convert/object_model.py:756 msgid "the variable \"{0}\" is waiting for a boolean as \"{1}\" but the attribute \"default\" is not a boolean (\"{2}\")" msgstr "" -#: src/rougail/convert/object_model.py:771 +#: src/rougail/convert/object_model.py:776 msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\" for variable \"{1}\"" msgstr "" -#: src/rougail/convert/object_model.py:776 +#: src/rougail/convert/object_model.py:781 msgid "the variable \"{0}\" has an invalid attribute \"{1}\", \"when\" and \"when_not\" cannot set together" msgstr "" -#: src/rougail/convert/object_model.py:784 +#: src/rougail/convert/object_model.py:789 msgid "\"when_not\" is not allowed in format version 1.0 for attribute \"{0}\" for variable \"{1}\"" msgstr "" -#: src/rougail/convert/object_model.py:840 +#: src/rougail/convert/object_model.py:845 msgid "cannot find variable \"{0}\" for the information \"{1}\" when calculating \"{2}\"" msgstr "" -#: src/rougail/convert/object_model.py:845 +#: src/rougail/convert/object_model.py:850 msgid "identifier not allowed for the information \"{0}\" when calculating \"{1}\"" msgstr "" -#: src/rougail/convert/object_model.py:897 +#: src/rougail/convert/object_model.py:902 msgid "\"when\" is not allowed in format version 1.0 for attribute \"{0}\"" msgstr "" -#: src/rougail/convert/object_model.py:903 -#: src/rougail/convert/object_model.py:913 +#: src/rougail/convert/object_model.py:908 +#: src/rougail/convert/object_model.py:918 msgid "the identifier has an invalid attribute \"{0}\", \"when\" and \"when_not\" cannot set together" msgstr "" -#: src/rougail/convert/object_model.py:939 +#: src/rougail/convert/object_model.py:944 msgid "the variable \"{0}\" is not a follower, so cannot have index type for \"{1}\"" msgstr "" @@ -330,7 +362,7 @@ msgid "internal error, {0} is not a dynamic variable" msgstr "" #: src/rougail/error.py:61 src/rougail/tiramisu.py:157 -#: src/rougail/user_datas.py:392 src/rougail/user_datas.py:395 +#: src/rougail/user_datas.py:407 src/rougail/user_datas.py:410 msgid "{0} in {1}" msgstr "" @@ -382,55 +414,55 @@ msgstr "" msgid "cannot calculating \"{0}\" attribute for variable \"{1}\" in {2} with parameters \"{3}\": {4}" msgstr "" -#: src/rougail/user_datas.py:135 +#: src/rougail/user_datas.py:145 msgid "cannot load variable path \"{0}\", the identifier \"{1}\" is not valid in {2}" msgstr "" -#: src/rougail/user_datas.py:218 +#: src/rougail/user_datas.py:228 msgid "the variable \"{0}\" contains secrets and should not be defined in {1}" msgstr "" -#: src/rougail/user_datas.py:257 +#: src/rougail/user_datas.py:268 msgid "loaded from {0}" msgstr "" -#: src/rougail/user_datas.py:297 +#: src/rougail/user_datas.py:308 msgid "cannot set the value \"{0}\" to the family {1}, it will be ignored when loading from {2}" msgstr "" -#: src/rougail/user_datas.py:309 -msgid "variable or family \"{0}\" does not exist, it will be ignored when loading from {1}" -msgstr "" - -#: src/rougail/user_datas.py:315 -msgid "\"{0}\" is the name of a dynamic family, it will be ignored when loading from {1}" -msgstr "" - -#: src/rougail/user_datas.py:321 +#: src/rougail/user_datas.py:319 src/rougail/user_datas.py:336 msgid "{0} loaded from {1}" msgstr "" -#: src/rougail/user_datas.py:349 +#: src/rougail/user_datas.py:324 +msgid "variable or family \"{0}\" does not exist, it will be ignored when loading from {1}" +msgstr "" + +#: src/rougail/user_datas.py:330 +msgid "\"{0}\" is the name of a dynamic family, it will be ignored when loading from {1}" +msgstr "" + +#: src/rougail/user_datas.py:364 msgid "variable {0} at index \"{1}\" is {2}, it will be ignored when loading from {3}" msgstr "" -#: src/rougail/user_datas.py:360 +#: src/rougail/user_datas.py:375 msgid "family {0} is {1}, {2} at index \"{3}\" will be ignored when loading from {4}" msgstr "" -#: src/rougail/user_datas.py:373 +#: src/rougail/user_datas.py:388 msgid "variable {0} is {1}, it will be ignored when loading from {2}" msgstr "" -#: src/rougail/user_datas.py:381 +#: src/rougail/user_datas.py:396 msgid "family {0} is {1}, {2} will be ignored when loading from {3}" msgstr "" -#: src/rougail/user_datas.py:401 +#: src/rougail/user_datas.py:416 msgid "the value \"{0}\" is an invalid {1} for {2} at index \"{3}\", {4}, it will be ignored when loading from {5}" msgstr "" -#: src/rougail/user_datas.py:415 +#: src/rougail/user_datas.py:430 msgid "the value \"{0}\" is an invalid {1} for {2}, {3}, it will be ignored when loading from {4}" msgstr "" diff --git a/src/rougail/annotator/property.py b/src/rougail/annotator/property.py index 5b5e7cfb3..ec4142ff4 100644 --- a/src/rougail/annotator/property.py +++ b/src/rougail/annotator/property.py @@ -166,7 +166,7 @@ class Annotator(Walk): raise DictConsistencyError(msg, 82, xmlfiles) if tag in PROPERTIES_MAKE_SENSE: msg = _( - 'invalid tag name "{0}" should not be name of an available properties' + 'invalid tag name "{0}" should not be the name of an available properties' ).format(tag) raise DictConsistencyError(msg, 82, xmlfiles) diff --git a/src/rougail/annotator/variable.py b/src/rougail/annotator/variable.py index ed3d83734..0bc351624 100644 --- a/src/rougail/annotator/variable.py +++ b/src/rougail/annotator/variable.py @@ -29,7 +29,7 @@ from tiramisu.error import display_list from rougail.i18n import _ from rougail.utils import calc_multi_for_type_variable from rougail.error import DictConsistencyError -from rougail.convert.object_model import Calculation, VariableCalculation, IndexCalculation +from rougail.convert.object_model import Calculation, VariableCalculation, VariableParam, IndexCalculation, JinjaCalculation from rougail.tiramisu import display_xmlfiles, RENAME_TYPE from warnings import warn @@ -147,6 +147,38 @@ class Annotator(Walk): # pylint: disable=R0903 if calculated_variable is not None: self._default_variable_copy_informations(variable, calculated_variable) self._convert_variable(variable) + if variable.multi and variable.params: + indexes_to_remove = [] + for idx, param in enumerate(variable.params): + if param.key == "multi_length": + jinja = f'{{% if var | length != {param.value} %}}{_("{0} values needed, but there are {{{{ var | length }}}}").format(param.value)}{{% endif %}}' + description = _('needs exactly {0} values').format(param.value) + elif param.key == "multi_max_length": + jinja = f'{{% if var | length > {param.value} %}}{_("a maximum of {0} values are needed, but there are {{{{ var | length }}}}").format(param.value)}{{% endif %}}' + description = _('needs a maximum of {0} values').format(param.value) + elif param.key == "multi_min_length": + jinja = f'{{% if var | length < {param.value} %}}{_("a minimum of {0} values are needed, but there are {{{{ var | length }}}}").format(param.value)}{{% endif %}}' + description = _('needs a minimum of {0} values').format(param.value) + else: + continue + indexes_to_remove.append(idx) + if variable.validators is None: + variable.validators = [] + + variable.validators.append( + JinjaCalculation(path=variable.path, + inside_list=True, + version=variable.version, + xmlfiles=variable.xmlfiles, + attribute_name="validators", + namespace=variable.namespace, + jinja=jinja, + description=description, + params=[VariableParam(variable.path, "validators", False, variable.xmlfiles, key="var", namespace=variable.namespace, type="variable", variable=variable.path, whole=True)], + ) + ) + for idx in reversed(indexes_to_remove): + variable.params.pop(idx) def _convert_variable_inference( self, @@ -189,9 +221,8 @@ class Annotator(Walk): # pylint: disable=R0903 and variable.path == calculated_variable.default.path ): msg = _( - 'the "{0}" default value is a calculation with itself'.format( + 'the "{0}" default value is a calculation with itself').format( variable.path - ) ) raise DictConsistencyError(msg, 75, variable.xmlfiles) self._convert_variable_multi(calculated_variable) diff --git a/src/rougail/locale/fr/LC_MESSAGES/rougail.mo b/src/rougail/locale/fr/LC_MESSAGES/rougail.mo index f49ad698f2d620fccd8ada138668c77baaf8ed50..dfc5f2cd8d885cec387ba40a927a442cf3d24cb5 100644 GIT binary patch delta 3696 zcmbW(d2AF_9Ki8ct^zHTmQq2EzHZB*^e&(R$|Y0;EFhO$W!in)PMw{tyR$ulxOfB; zqhhjwn5bzYAzGvHX!wU{G}a>;jfzD75Rd3T9)D;e#)QP<`M>;I1PWs={Rw! zQrF`gT!9wK`Nwc3K95)9+jtp{El{cyXX9dAfm3KiECBBCfFn>lcq3O7h<9%3#r}0Mo5HtRWN`e_3#O+*o z0-Ny?k_5GvX-~oqT#X)Hi)U~y{uo+F-X--ld`L~)fO7qLl(l~km*7t*_rG!$`InL1 zM}a$xt`unscjL#{jWs-7d;&LMDeEcE zi{Vy$ZXWqxPba4|xN#%OgYOT0ADcKX*1`EG$^)Ool{lXK%MI6}WbS^HfqafOu4BFA z_!*QXDJ=J^Ud_Zhj+bQUkPQ_>{wXz2B0Exj zfU*lN;8pko{(_4ZDCOdUg-TtAC(vN#Je?Lg%NHr-;A7Z;ldlL;c^&q0d=iq8-G#DUPvc%ZhcbXF_S#Z3$QaZkNK)0S$f{=4mvlCA;un;ZHgXq@_n>6t zG&bT};rT+I&ZJa5%J=u6%=iSZ$9_D7-=pl3t<^yh-icCUeW>wkTrc~7Qcdu~CX|t% zK*_)lI29|ni)5$)Wob_0jrbADnwPPVThYS~d>yaB+WMeYI`9C;Z(<(K=jJ3+)nNnA zSNrHNIdvSR%3nm8@eKA#E*`)pG$;c(gUfIxc}-yxZpJ~p1*dVb4LeY-pTp_6f%T99 z?8TcfhM6sN&d`yy9D8-({Ln`9IB%mY#b?MWsWD7XW?0RKJfIzAh8Hl3%a?O=?89c9 z!24P56T?>g1Z6_2R+4}D!EqK+Qg;#Mhs~7qetZKZL*7*;Yrf1pT^H=*hf&Utxjxv( z2Fo~hkkwER;w&6Q>P~%%GSECmbqsf*k@L74*KG*?IzE!2BSm)!Wf$yZ;q$Q%FT6kjpHtHXbXfZryBPDWXG%ER9&xfmf>x{Uvy2KxScU5cokxQ(Dj{C&>E zl@zJ$_0@z_ejyPh<`B{r65W1JsasJpD(l@qP#XTemwJ*mnnsVBdxFUK{+6r!A%K}h2T z<-hx-usR6YYC}!-v9xgkYG0@nofKeMcr5Rgv0;A`N{vY&wh=Cona+n4Tn!;@3?Xkl zsp><7v_yda->*1*d3jLCEMm8nbZxgS7137G=!EO^YOBk#9jnDLy4&{JwdHw9yCv-z z9XXsbPON(PM6+wfP1%u%jwO=1%Szh*kHT*yl6G^a<+UG)3>=#D{rF7W>apYLxK70M z;o2j7-AS92|4`SMsEJl;o}s;V!!TqhhiP(CeY&~is4p);B2G)d1kse!)YEjc@6xC~s6Iw3WDb+l22S51%A z>XGO_@{s**#tXF(jw3p1VpiJmf&^(>p44hNt!c;d?1UREiS5Zk3_M)&X8y82ZleD~ zBC`j|YbMuK)h^TZb;}#-vnR{nY8981Tj}BCg`+p=WU7*rOqVb9YQqBjQw5B?OPJ(;cbEK; zg*5Q~;=T#lNPSTSb?zqOI=V3J8ZC>Rv%rhqV9z delta 2522 zcmYk;drXyO9KiA4;VyEC!`*;$#N>Vxg-{>}ko!eZED$&#ow&$F!(?r(Q)}R?w7F9e zt(?qN&NYV}v%m5W7F*4&CCznNmuX`)=d4z3rEB#4z3)rwnLj?y^T2tZ=lMO)^Bz}U zw$04gJm1>`UKPp&kwm=WFQOe`!Tg}~trMxher(5i+=qYQ5H^L1WZ@-j!ym90^Vf?c z;z`_$=dAW;ct7o*F;&DP0bwFr=}5<1+>beU9Aoe@-iKE)8o$LF{1r>FDBSEnj0v=- zu>?jJ@C-KKZPd&aM~M{R39Mp#xk5!(WV4HeU@ejwX+!2*Os>1$3Ye^cLy_f5JwLC5^^}u$}f9bm8ylVbZcER)p=80j$I^EXNC|dwd&{ zu_Mmh%SqG+%%KkWH)>|8$@io95?1314q_(zqWz~(7kUdjFh7y}cT<_>qzvFq)Ku1P z5ShZ$mT{bzTG}U32fU8E(7}n_iHA@hd>M7%dzKZGG zScj*q{;!d_$z9aHcV?Lj?7^LS{|{5?;};*Ip7sPTDcd9sSdW9~#0AueUPE1R4%6p` zN*`)QCQwtqjE!h#*}A1YsHtDT5wzurY{yaT*8Besl^#0$^F`KUKQdVvLmg-qd8S-N zJ;i^au5dTA4aPZa!+F$+{D#H2mjg11FJd#U;vhB`n*EnBn(-xrQFP!kY{hzP!C5?l zE2ydM+Gf7Np211l=TRq~!hSu5Pvhfw16^3pEcEl|Z~&9pU!CZ4sDFPAJ(`l@67z%e zsMjNe{OH8omMf?!b?-1IxPUsqDzb;-DmAa)+gM5a7FJ<48@>m}u?ZKkA0x`mTX3kH zVe~pI(xIt~;i#)qIE>#|?V1Yn`n`*KsxKgmm(MW~11rr_?m(Sr3(nx{=tjrG=Ixlq zUfSPb7nbS!w}Hwm(+$HL7>{?*hPpZ}x}PNBzv7@aPUzj&0d(6m^_o3>PA8%73Fc=^ zluV01u~vAzad?e1N7LxAenaMrH=Ukb-7`I4I@A3`H9^LW!?X^=3B4gYVJ&q8N5%N| zV}ZtXOGeI}@ooU)3r*EUZzepN=1_w7it%-;>02uYsH9sB&Xn;cTl-yzRnc_nVH&gA zQI@+<_k0t<%`?i7rQRalHnyJp|F5v!#y6V2c(mxX8zHi^VU>PMy)l_Yq}8s$SgXFl za*Y71(uW&~RI7bZ#}A}2L5y0RPD~;O2|JNNq!9avwUSN6kI>W2*)^_J55^H(f8#$a zF4R&<@QRUqLa()?P7S%oQ=P+;&hZJ~TNI&*rU9xaiAETnzJOq~(Sd z