diff --git a/app/comp/bonus_spo.py b/app/comp/bonus_spo.py index d6abcb78..e822394d 100644 --- a/app/comp/bonus_spo.py +++ b/app/comp/bonus_spo.py @@ -57,7 +57,7 @@ class BonusSport: # Attributs virtuels: seuil_moy_gen = None proportion_point = None - bonus_moy_gen_limit = None + bonus_max = None name = "virtual" @@ -217,147 +217,13 @@ class BonusSportAdditif(BonusSport): self.bonus_moy_gen = pd.Series( bonus_moy_gen_arr, index=self.etuds_idx, dtype=float ) - if self.bonus_moy_gen_limit is not None: - # Seuil: bonus (sur moy. gen.) limité à bonus_moy_gen_limit points - self.bonus_moy_gen = self.bonus_moy_gen.clip(upper=self.bonus_moy_gen_limit) + if self.bonus_max is not None: + # Seuil: bonus (sur moy. gen.) limité à bonus_max points + self.bonus_moy_gen = self.bonus_moy_gen.clip(upper=self.bonus_max) # Laisse bonus_ues à None, en APC le bonus moy. gen. sera réparti sur les UEs. -# bonus_ue = np.stack([modimpl_coefs_spo.T] * nb_ues) - - -class BonusIUTV(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT Villetaneuse - - Les étudiants de l'IUT peuvent suivre des enseignements optionnels - de l'Université Paris 13 (sports, musique, deuxième langue, - culture, etc) non rattachés à une unité d'enseignement. Les points - au-dessus de 10 sur 20 obtenus dans chacune des matières - optionnelles sont cumulés et 5% de ces points cumulés s'ajoutent à - la moyenne générale du semestre déjà obtenue par l'étudiant. - """ - - name = "bonus_iutv" - pass # oui, c'ets le bonus par défaut - - -class BonusDirect(BonusSportAdditif): - """Bonus direct: les points sont directement ajoutés à la moyenne générale. - Les coefficients sont ignorés: tous les points de bonus sont sommés. - (rappel: la note est ramenée sur 20 avant application). - """ - - name = "bonus_direct" - seuil_moy_gen = 0.0 # tous les points sont comptés - proportion_point = 1.0 - - -class BonusStDenis(BonusIUTV): - """Semblable à bonus_iutv mais sans coefficients et total limité à 0.5 points.""" - - name = "bonus_iut_stdenis" - bonus_moy_gen_limit = 0.5 - - -class BonusColmar(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT Colmar. - - Les étudiants de l'IUT peuvent suivre des enseignements optionnels - de l'U.H.A. (sports, musique, deuxième langue, culture, etc) non - rattachés à une unité d'enseignement. Les points au-dessus de 10 - sur 20 obtenus dans chacune des matières optionnelles sont cumulés - dans la limite de 10 points. 5% de ces points cumulés s'ajoutent à - la moyenne générale du semestre déjà obtenue par l'étudiant. - """ - - # note: cela revient à dire que l'on ajoute 5% des points au dessus de 10, - # et qu'on limite à 5% de 10, soit 0.5 points - # ce bonus est donc strictement identique à celui de St Denis (BonusIUTStDenis) - name = "bonus_colmar" - bonus_moy_gen_limit = 0.5 - - -class BonusTours(BonusDirect): - """Calcul bonus sport & culture IUT Tours. - - Les notes des UE bonus (ramenées sur 20) sont sommées - et 1/40 (2,5%) est ajouté aux moyennes: soit à la moyenne générale, - soit pour le BUT à chaque moyenne d'UE. - - Le bonus total est limité à 1 point. - """ - - name = "bonus_tours" - bonus_moy_gen_limit = 1.0 # - seuil_moy_gen = 0.0 # seuls les points au dessus du seuil sont comptés - proportion_point = 1.0 / 40.0 - - -def bonus_iutlemans(notes_sport, coefs, infos=None): - # Calcul bonus modules optionnels (sport, culture), règle IUT Le Mans - # La moyenne de chacune des UE du semestre sera majorée à hauteur de 2% du cumul des points supérieurs à 10 obtenus en matières optionnelles, - # dans la limite de 0,5 point. - points = sum([x - 10 for x in notes_sport if x > 10]) # points au dessus de 10 - bonus = points * 0.02 # ou / 20 - return min(bonus, 0.5) # bonus limité à 0.5 point - - -class BonusLeMans(BonusSportAdditif): - """Calcul bonus modules optionnels (sport, culture), règle IUT Le Mans - - La moyenne de chacune des UE du semestre sera majorée à hauteur de - 2% du cumul des points supérieurs à 10 obtenus en matières optionnelles, - dans la limite de 0,5 point. - """ - - name = "bonus_iutlemans" - seuil_moy_gen = 10.0 # points comptés au dessus de 10. - proportion_point = 0.02 - bonus_moy_gen_limit = 0.5 # - - -# Bonus simple, mais avec changement de paramètres en 2010 ! -class BonusLille(BonusSportAdditif): - """Calcul bonus modules optionels (sport, culture), règle IUT Villeneuve d'Ascq - - Les étudiants de l'IUT peuvent suivre des enseignements optionnels - de l'Université Lille 1 (sports, etc) non rattachés à une unité d'enseignement. - - Les points au-dessus de 10 sur 20 obtenus dans chacune des matières - optionnelles sont cumulés et 4% (2% avant août 2010) de ces points cumulés - s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant. - """ - - name = "bonus_lille" - seuil_moy_gen = 10.0 # points comptés au dessus de 10. - - def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): - """calcul du bonus""" - # La date du semestre ? - if self.formsemestre.date_debut > datetime.date(2010, 8, 1): - self.proportion_point = 0.04 - else: - self.proportion_point = 0.02 - return super().compute_bonus( - sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan - ) - - -class BonusMulhouse(BonusSportAdditif): - """Calcul bonus modules optionnels (sport, culture), règle IUT de Mulhouse - - La moyenne de chacune des UE du semestre sera majorée à hauteur de - 5% du cumul des points supérieurs à 10 obtenus en matières optionnelles, - dans la limite de 0,5 point. - """ - - name = "bonus_iutmulhouse" - seuil_moy_gen = 10.0 # points comptés au dessus de 10. - proportion_point = 0.05 - bonus_moy_gen_limit = 0.5 # - - class BonusSportMultiplicatif(BonusSport): """Bonus sport qui multiplie les moyennes d'UE par un facteur""" @@ -381,8 +247,12 @@ class BonusSportMultiplicatif(BonusSport): factor = (notes - self.seuil_moy_gen) * self.amplitude # 5% si note=20 factor[factor <= 0] = 0.0 # note < seuil_moy_gen, pas de bonus - # S'applique qu'aux moyennes d'UE + # Ne s'applique qu'aux moyennes d'UE bonus = self.etud_moy_ue * factor + if self.bonus_max is not None: + # Seuil: bonus limité à bonus_max points + bonus.clip(upper=self.bonus_max, inplace=True) + self.bonus_ues = bonus # DataFrame if not self.formsemestre.formation.is_apc(): @@ -390,6 +260,91 @@ class BonusSportMultiplicatif(BonusSport): self.bonus_moy_gen = bonus +class BonusDirect(BonusSportAdditif): + """Bonus direct: les points sont directement ajoutés à la moyenne générale. + Les coefficients sont ignorés: tous les points de bonus sont sommés. + (rappel: la note est ramenée sur 20 avant application). + """ + + name = "bonus_direct" + displayed_name = 'Bonus "direct"' + seuil_moy_gen = 0.0 # tous les points sont comptés + proportion_point = 1.0 + + +class BonusBethune(BonusSportMultiplicatif): + """Calcul bonus modules optionels (sport), règle IUT de Béthune. + + 5% des points au dessus de 10., limité à 0.5 point de bonus. + """ + + name = "bonus_iutbethune" + displayed_name = "IUT de Béthune" + seuil_moy_gen = 10.0 + amplitude = 0.005 + bonus_max = 0.5 # plafonnement à 0.5 points + + +class BonusBezier(BonusSportAdditif): + """Calcul bonus modules optionels (sport, culture), règle IUT de Bézier. + + Les étudiants de l'IUT peuvent suivre des enseignements optionnels + sport , etc) non rattachés à une unité d'enseignement. Les points + au-dessus de 10 sur 20 obtenus dans chacune des matières + optionnelles sont cumulés et 3% de ces points cumulés s'ajoutent à + la moyenne générale du semestre déjà obtenue par l'étudiant, dans + la limite de 0,3 points. + """ + + # note: cela revient à dire que l'on ajoute 5% des points au dessus de 10, + # et qu'on limite à 5% de 10, soit 0.5 points + # ce bonus est donc strictement identique à celui de St Denis (BonusIUTStDenis) + name = "bonus_iutbeziers" + displayed_name = "IUT de Bézier" + bonus_max = 0.3 + seuil_moy_gen = 10.0 # tous les points sont comptés + proportion_point = 0.03 + + +class BonusBordeaux1(BonusSportMultiplicatif): + """Calcul bonus modules optionels (sport, culture), règle IUT Bordeaux 1, sur moyenne générale et UE + + Les étudiants de l'IUT peuvent suivre des enseignements optionnels + de l'Université Bordeaux 1 (sport, théâtre) non rattachés à une unité d'enseignement. + En cas de double activité, c'est la meilleure des 2 notes qui compte. + Chaque point au-dessus de 10 sur 20 obtenus dans cet enseignement correspond à un % + qui augmente la moyenne de chaque UE et la moyenne générale. + Formule : le % = points>moyenne / 2 + Par exemple : sport 13/20 : chaque UE sera multipliée par 1+0,015, ainsi que la moyenne générale. + + Calcul ici du bonus sur moyenne générale et moyennes d'UE non capitalisées. + + """ + + pass # XXX en attente de Cédric + + +class BonusColmar(BonusSportAdditif): + """Calcul bonus modules optionels (sport, culture), règle IUT Colmar. + + Les étudiants de l'IUT peuvent suivre des enseignements optionnels + de l'U.H.A. (sports, musique, deuxième langue, culture, etc) non + rattachés à une unité d'enseignement. Les points au-dessus de 10 + sur 20 obtenus dans chacune des matières optionnelles sont cumulés + dans la limite de 10 points. 5% de ces points cumulés s'ajoutent à + la moyenne générale du semestre déjà obtenue par l'étudiant. + """ + + # note: cela revient à dire que l'on ajoute 5% des points au dessus de 10, + # et qu'on limite à 5% de 10, soit 0.5 points + # ce bonus est donc strictement identique à celui de St Denis (BonusIUTStDenis) + name = "bonus_colmar" + displayed_name = "IUT de Colmar" + bonus_max = 0.5 + seuil_moy_gen = 10.0 # tous les points sont comptés + proportion_point = 0.05 + + class BonusGrenobleIUT1(BonusSportMultiplicatif): """Bonus IUT1 de Grenoble @@ -409,6 +364,7 @@ class BonusGrenobleIUT1(BonusSportMultiplicatif): """ name = "bonus_iut1grenoble_2017" + displayed_name = "IUT de Grenoble 1" # C'est un bonus "multiplicatif": on l'exprime en additif, # sur chaque moyenne d'UE m_0 # Augmenter de 5% correspond à multiplier par a=1.05 @@ -428,6 +384,20 @@ class BonusGrenobleIUT1(BonusSportMultiplicatif): super().compute_bonus(sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan) +class BonusLaRochelle(BonusSportAdditif): + """Calcul bonus modules optionels (sport, culture), règle IUT de La Rochelle. + + Si la note de sport est comprise entre 0 et 10 : pas d'ajout de point. + Si la note de sport est comprise entre 10 et 20 : ajout de 1% de cette + note sur la moyenne générale du semestre (ou sur les UE en BUT). + """ + + name = "bonus_iutlr" + displayed_name = "IUT de La Rochelle" + seuil_moy_gen = 10.0 # tous les points sont comptés + proportion_point = 0.01 + + class BonusLeHavre(BonusSportMultiplicatif): """Bonus sport IUT du Havre sur moyenne générale et UE @@ -436,10 +406,84 @@ class BonusLeHavre(BonusSportMultiplicatif): """ name = "bonus_iutlh" + displayed_name = "IUT du Havre" seuil_moy_gen = 10.0 # seuls les points au dessus du seuil sont comptés amplitude = 0.005 # multiplie les points au dessus du seuil +class BonusLeMans(BonusSportAdditif): + """Calcul bonus modules optionnels (sport, culture), règle IUT Le Mans + + La moyenne de chacune des UE du semestre sera majorée à hauteur de + 2% du cumul des points supérieurs à 10 obtenus en matières optionnelles, + dans la limite de 0,5 point. + """ + + name = "bonus_iutlemans" + displayed_name = "IUT du Mans" + seuil_moy_gen = 10.0 # points comptés au dessus de 10. + proportion_point = 0.02 + bonus_max = 0.5 # + + +# Bonus simple, mais avec changement de paramètres en 2010 ! +class BonusLille(BonusSportAdditif): + """Calcul bonus modules optionels (sport, culture), règle IUT Villeneuve d'Ascq + + Les étudiants de l'IUT peuvent suivre des enseignements optionnels + de l'Université Lille 1 (sports, etc) non rattachés à une unité d'enseignement. + + Les points au-dessus de 10 sur 20 obtenus dans chacune des matières + optionnelles sont cumulés et 4% (2% avant août 2010) de ces points cumulés + s'ajoutent à la moyenne générale du semestre déjà obtenue par l'étudiant. + """ + + name = "bonus_lille" + displayed_name = "IUT de Lille" + seuil_moy_gen = 10.0 # points comptés au dessus de 10. + + def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): + """calcul du bonus""" + # La date du semestre ? + if self.formsemestre.date_debut > datetime.date(2010, 8, 1): + self.proportion_point = 0.04 + else: + self.proportion_point = 0.02 + return super().compute_bonus( + sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan + ) + + +class BonusLyonProvisoire(BonusSportAdditif): + """Calcul bonus modules optionnels (sport, culture), règle IUT de Lyon (provisoire) + + Les points au-dessus de 10 sur 20 obtenus dans chacune des matières + optionnelles sont cumulés et 1,8% de ces points cumulés + s'ajoutent aux moyennes, dans la limite d'1/2 point. + """ + + name = "bonus_lyon_provisoire" + displayed_name = "IUT de Lyon (provisoire)" + seuil_moy_gen = 10.0 # points comptés au dessus de 10. + proportion_point = 0.018 + bonus_max = 0.5 + + +class BonusMulhouse(BonusSportAdditif): + """Calcul bonus modules optionnels (sport, culture), règle IUT de Mulhouse + + La moyenne de chacune des UE du semestre sera majorée à hauteur de + 5% du cumul des points supérieurs à 10 obtenus en matières optionnelles, + dans la limite de 0,5 point. + """ + + name = "bonus_iutmulhouse" + displayed_name = "IUT de Mulhouse" + seuil_moy_gen = 10.0 # points comptés au dessus de 10. + proportion_point = 0.05 + bonus_max = 0.5 # + + class BonusNantes(BonusSportAdditif): """IUT de Nantes (Septembre 2018) @@ -457,24 +501,60 @@ class BonusNantes(BonusSportAdditif): """ name = "bonus_nantes" + displayed_name = "IUT de Nantes" seuil_moy_gen = 0.0 # seuls les points au dessus du seuil sont comptés proportion_point = 1 # multiplie les points au dessus du seuil - bonus_moy_gen_limit = 0.5 # plafonnement à 0.5 points + bonus_max = 0.5 # plafonnement à 0.5 points class BonusRoanne(BonusSportAdditif): """IUT de Roanne. - Le bonus est compris entre 0 et 0.35 point + Le bonus est compris entre 0 et 0.6 points et est toujours appliqué aux UEs. """ name = "bonus_iutr" + displayed_name = "IUT de Roanne" seuil_moy_gen = 0.0 - bonus_moy_gen_limit = 0.35 # plafonnement à 0.35 points + bonus_max = 0.6 # plafonnement à 0.6 points apply_bonus_mg_to_ues = True # sur les UE, même en DUT et LP +class BonusStDenis(BonusSportAdditif): + """Calcul bonus modules optionels (sport, culture), règle IUT Saint-Denis + + Les étudiants de l'IUT peuvent suivre des enseignements optionnels + de l'Université Paris 13 (sports, musique, deuxième langue, + culture, etc) non rattachés à une unité d'enseignement. Les points + au-dessus de 10 sur 20 obtenus dans chacune des matières + optionnelles sont cumulés et 5% de ces points cumulés s'ajoutent à + la moyenne générale du semestre déjà obtenue par l'étudiant, dans la limite + d'1/2 point. + """ + + name = "bonus_iut_stdenis" + displayed_name = "IUT de Saint-Denis" + bonus_max = 0.5 + + +class BonusTours(BonusDirect): + """Calcul bonus sport & culture IUT Tours. + + Les notes des UE bonus (ramenées sur 20) sont sommées + et 1/40 (2,5%) est ajouté aux moyennes: soit à la moyenne générale, + soit pour le BUT à chaque moyenne d'UE. + + Le bonus total est limité à 1 point. + """ + + name = "bonus_tours" + displayed_name = "IUT de Tours" + bonus_max = 1.0 # + seuil_moy_gen = 0.0 # seuls les points au dessus du seuil sont comptés + proportion_point = 1.0 / 40.0 + + class BonusVilleAvray(BonusSport): """Bonus modules optionels (sport, culture), règle IUT Ville d'Avray. @@ -488,6 +568,7 @@ class BonusVilleAvray(BonusSport): """ name = "bonus_iutva" + displayed_name = "IUT de Ville d'Avray" def compute_bonus(self, sem_modimpl_moys_inscrits, modimpl_coefs_etuds_no_nan): """calcul du bonus""" @@ -503,13 +584,29 @@ class BonusVilleAvray(BonusSport): self.bonus_moy_gen = pd.Series( bonus_moy_gen_arr, index=self.etuds_idx, dtype=float ) - if self.bonus_moy_gen_limit is not None: - # Seuil: bonus (sur moy. gen.) limité à bonus_moy_gen_limit points - self.bonus_moy_gen = self.bonus_moy_gen.clip(upper=self.bonus_moy_gen_limit) + if self.bonus_max is not None: + # Seuil: bonus (sur moy. gen.) limité à bonus_max points + self.bonus_moy_gen = self.bonus_moy_gen.clip(upper=self.bonus_max) # Laisse bonus_ues à None, en APC le bonus moy. gen. sera réparti sur les UEs. +class BonusIUTV(BonusSportAdditif): + """Calcul bonus modules optionels (sport, culture), règle IUT Villetaneuse + + Les étudiants de l'IUT peuvent suivre des enseignements optionnels + de l'Université Paris 13 (sports, musique, deuxième langue, + culture, etc) non rattachés à une unité d'enseignement. Les points + au-dessus de 10 sur 20 obtenus dans chacune des matières + optionnelles sont cumulés et 5% de ces points cumulés s'ajoutent à + la moyenne générale du semestre déjà obtenue par l'étudiant. + """ + + name = "bonus_iutv" + displayed_name = "IUT de Villetaneuse" + pass # oui, c'ets le bonus par défaut + + def get_bonus_class_dict(start=BonusSport, d=None): """Dictionnaire des classes de bonus (liste les sous-classes de BonusSport ayant un nom) diff --git a/app/forms/main/config_main.py b/app/forms/main/config_main.py index e0b349e4..d6536a8d 100644 --- a/app/forms/main/config_main.py +++ b/app/forms/main/config_main.py @@ -42,8 +42,8 @@ class ScoDocConfigurationForm(FlaskForm): bonus_sport_func_name = SelectField( label="Fonction de calcul des bonus sport&culture", choices=[ - (x, x if x else "Aucune") - for x in ScoDocSiteConfig.get_bonus_sport_class_names() + (name, displayed_name if name else "Aucune") + for (name, displayed_name) in ScoDocSiteConfig.get_bonus_sport_class_list() ], ) submit = SubmitField("Valider") diff --git a/app/models/config.py b/app/models/config.py index da98998c..9c9c5638 100644 --- a/app/models/config.py +++ b/app/models/config.py @@ -124,7 +124,7 @@ class ScoDocSiteConfig(db.Model): If class_name not found in module bonus_sport, returns None and flash a warning. """ - if class_name is None: + if not class_name: # None or "" c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first() if c is None: return None @@ -140,12 +140,22 @@ class ScoDocSiteConfig(db.Model): return klass @classmethod - def get_bonus_sport_class_names(cls): + def get_bonus_sport_class_names(cls) -> list: """List available bonus class names (starting with empty string to represent "no bonus function"). """ return [""] + sorted(bonus_spo.get_bonus_class_dict().keys()) + @classmethod + def get_bonus_sport_class_list(cls) -> list[tuple]: + """List available bonus class names + (starting with empty string to represent "no bonus function"). + """ + d = bonus_spo.get_bonus_class_dict() + class_list = [(name, d[name].displayed_name) for name in d.keys()] + class_list.sort(key=lambda x: x[1].replace(" du ", " de ")) + return [("", "")] + class_list + @classmethod def get_bonus_sport_func(cls): """Fonction bonus_sport ScoDoc 7 XXX diff --git a/app/scodoc/bonus_sport.py b/app/scodoc/bonus_sport.py index 1e754f82..5fc3b8b4 100644 --- a/app/scodoc/bonus_sport.py +++ b/app/scodoc/bonus_sport.py @@ -375,7 +375,7 @@ def bonus_iutBordeaux1(notes_sport, coefs, infos=None): return bonus -def bonus_iuto(notes_sport, coefs, infos=None): +def bonus_iuto(notes_sport, coefs, infos=None): # OBSOLETE => EN ATTENTE (27/01/2022) """Calcul bonus modules optionels (sport, culture), règle IUT Orleans * Avant aout 2013 Un bonus de 2,5% de la note de sport est accordé à chaque UE sauf diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 788f4b93..5c4741f7 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -390,9 +390,9 @@ def ue_edit(ue_id=None, create=False, formation_id=None): submitlabel=submitlabel, ) if tf[0] == 0: - X = """
- """ - return "\n".join(H) + tf[1] + X + html_sco_header.sco_footer() + ue_div = """""" + bonus_div = """""" + return "\n".join(H) + tf[1] + bonus_div + ue_div + html_sco_header.sco_footer() else: if create: if not tf[2]["ue_code"]: diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index 684df8a0..c5758cb5 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -881,6 +881,19 @@ div.sco_help { span.wtf-field ul.errors li { color: red; } + +#bonus_description { + color:rgb(6, 73, 6); + padding: 5px; + margin-top:5px; + border: 2px solid blue; + border-radius: 5px; + background-color: cornsilk; +} +#bonus_description div.bonus_description_head{ + font-weight: bold; +} + .configuration_logo div.img { } diff --git a/app/static/js/edit_ue.js b/app/static/js/edit_ue.js index 34e8e9c8..8424496c 100644 --- a/app/static/js/edit_ue.js +++ b/app/static/js/edit_ue.js @@ -3,8 +3,26 @@ $().ready(function () { update_ue_list(); $("#tf_ue_code").bind("keyup", update_ue_list); + + $("select#tf_type").change(function () { + update_bonus_description(); + }); + update_bonus_description(); }); +function update_bonus_description() { + var ue_type = $("#tf_type")[0].value; + if (ue_type == "1") { /* UE SPORT */ + $("#bonus_description").show(); + var query = "/ScoDoc/get_bonus_description/default"; + $.get(query, '', function (data) { + $("#bonus_description").html(data); + }); + } else { + $("#bonus_description").html(""); + $("#bonus_description").hide(); + } +} function update_ue_list() { var ue_id = $("#tf_ue_id")[0].value; diff --git a/app/templates/configuration.html b/app/templates/configuration.html index 888d9591..823772de 100644 --- a/app/templates/configuration.html +++ b/app/templates/configuration.html @@ -30,8 +30,8 @@