From e08363461446c9e1af85145b3bc70c736b277296 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Wed, 4 Feb 2026 21:25:31 +0100 Subject: [PATCH 1/8] Format --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 0c905d7..112ce70 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use eframe::egui; use eframe::egui::KeyboardShortcut; -use log::{info, warn, error}; +use log::{error, info, warn}; use billy_sheet::gui::SheetGui; @@ -38,7 +38,7 @@ impl Default for Gui { impl eframe::App for Gui { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { egui::TopBottomPanel::top("menu").show(ctx, |ui| { - egui::MenuBar::new().ui(ui, |ui| { + egui::MenuBar::new().ui(ui, |ui| { egui::widgets::global_theme_preference_buttons(ui); ui.menu_button("File", |ui| { if ui.button("Open (Ctrl + O)").clicked() { From 058a9eeea43296a29278421aabebf04bd815188c Mon Sep 17 00:00:00 2001 From: Pcornat Date: Wed, 4 Feb 2026 21:25:57 +0100 Subject: [PATCH 2/8] Using enum to store characteristic data --- src/sheet.rs | 93 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/src/sheet.rs b/src/sheet.rs index ac177f8..aa270e5 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -15,10 +15,10 @@ pub enum Classe { #[derive(Debug, Serialize, Deserialize)] enum CharacteristicType { - Address, - Stamina, - Luck, - Skill, + Address(Characteristic), + Stamina(Characteristic), + Luck(Characteristic), + Skill(Characteristic), } #[derive(Debug, Serialize, Deserialize)] @@ -26,10 +26,10 @@ pub struct CharacterSheet { character_class: Classe, /// Field to write the personality/ pub character: String, - address: Characteristic, - stamina: Characteristic, - luck: Characteristic, - skill: Characteristic, + address: CharacteristicType, + stamina: CharacteristicType, + luck: CharacteristicType, + skill: CharacteristicType, health: u32, armor: u32, damage: u32, @@ -51,16 +51,32 @@ impl CharacterSheet { &self.character } pub fn address(&self) -> &Characteristic { - &self.address + if let CharacteristicType::Address(addr) = &self.address { + addr + } else { + unreachable!() + } } pub fn stamina(&self) -> &Characteristic { - &self.stamina + if let CharacteristicType::Stamina(sta) = &self.stamina { + sta + } else { + unreachable!() + } } pub fn luck(&self) -> &Characteristic { - &self.luck + if let CharacteristicType::Luck(luck) = &self.luck { + luck + } else { + unreachable!() + } } pub fn skill(&self) -> &Characteristic { - &self.skill + if let CharacteristicType::Skill(sk) = &self.skill { + sk + } else { + unreachable!() + } } pub fn health(&self) -> u32 { self.health @@ -151,7 +167,6 @@ impl SheetGui for CharacterSheet { #[derive(Debug, Serialize, Deserialize)] pub struct Characteristic { - characteristic_type: CharacteristicType, pub base: u32, pub carac: u32, pub materiel: u32, @@ -163,33 +178,37 @@ impl Default for CharacterSheet { Self { character_class: Classe::Warrior, character: "Billy".to_string(), - address: Characteristic { - characteristic_type: CharacteristicType::Address, - base: 0, - carac: 0, - materiel: 0, - additional: 1, + address: CharacteristicType::Address { + 0: Characteristic { + base: 0, + carac: 0, + materiel: 0, + additional: 1, + }, }, - stamina: Characteristic { - characteristic_type: CharacteristicType::Stamina, - base: 2, - carac: 0, - materiel: 0, - additional: 0, + stamina: CharacteristicType::Stamina { + 0: Characteristic { + base: 2, + carac: 0, + materiel: 0, + additional: 0, + }, }, - luck: Characteristic { - characteristic_type: CharacteristicType::Luck, - base: 3, - carac: 0, - materiel: 0, - additional: 0, + luck: CharacteristicType::Luck { + 0: Characteristic { + base: 3, + carac: 0, + materiel: 0, + additional: 0, + }, }, - skill: Characteristic { - characteristic_type: CharacteristicType::Skill, - base: 2, - carac: 0, - materiel: 0, - additional: 0, + skill: CharacteristicType::Skill { + 0: Characteristic { + base: 2, + carac: 0, + materiel: 0, + additional: 0, + }, }, health: 0, armor: 0, From db448adae31f1f9408630a11accc2ea4ede00a24 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Wed, 4 Feb 2026 21:29:05 +0100 Subject: [PATCH 3/8] Using tuple initialization --- src/sheet.rs | 56 ++++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/sheet.rs b/src/sheet.rs index aa270e5..577dce5 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -178,38 +178,30 @@ impl Default for CharacterSheet { Self { character_class: Classe::Warrior, character: "Billy".to_string(), - address: CharacteristicType::Address { - 0: Characteristic { - base: 0, - carac: 0, - materiel: 0, - additional: 1, - }, - }, - stamina: CharacteristicType::Stamina { - 0: Characteristic { - base: 2, - carac: 0, - materiel: 0, - additional: 0, - }, - }, - luck: CharacteristicType::Luck { - 0: Characteristic { - base: 3, - carac: 0, - materiel: 0, - additional: 0, - }, - }, - skill: CharacteristicType::Skill { - 0: Characteristic { - base: 2, - carac: 0, - materiel: 0, - additional: 0, - }, - }, + address: CharacteristicType::Address(Characteristic { + base: 0, + carac: 0, + materiel: 0, + additional: 1, + }), + stamina: CharacteristicType::Stamina(Characteristic { + base: 2, + carac: 0, + materiel: 0, + additional: 0, + }), + luck: CharacteristicType::Luck(Characteristic { + base: 3, + carac: 0, + materiel: 0, + additional: 0, + }), + skill: CharacteristicType::Skill(Characteristic { + base: 2, + carac: 0, + materiel: 0, + additional: 0, + }), health: 0, armor: 0, damage: 0, From d85583895cfffea054e4a9b1ae1a1a1cb112d381 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Thu, 5 Feb 2026 14:08:47 +0100 Subject: [PATCH 4/8] Adding objects in Billy logic --- src/billy_objects.rs | 193 +++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/sheet.rs | 2 +- 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/billy_objects.rs diff --git a/src/billy_objects.rs b/src/billy_objects.rs new file mode 100644 index 0000000..f133028 --- /dev/null +++ b/src/billy_objects.rs @@ -0,0 +1,193 @@ +use crate::billy_objects::Weapons::*; +use crate::sheet::CharacteristicType; +use crate::sheet::CharacteristicType::*; +use serde::{Deserialize, Serialize}; + +pub trait GenericObject { + fn add_armor(&self) -> u32 { + 0 + } + fn add_critique(&self) -> u32 { + 0 + } + fn add_damage(&self) -> u32 { + 0 + } + fn add_materiel(&self, in_type: &CharacteristicType) -> i32; +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Weapons { + Sword, + Lance, + Morgenstern, + Bow, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Equipments { + Chainmail, + CookingPot, + PamphletTourist, + MedicKit, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Tools { + Fourche, + Dagger, + RockClimbingKit, + SackOfGrain, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum Objects { + Weapons(Weapons), + Equipments(Equipments), + Tools(Tools), +} + +impl GenericObject for Weapons { + fn add_damage(&self) -> u32 { + if let Morgenstern = &self { + 1 + } else { + 0 + } + } + + fn add_materiel(&self, in_type: &CharacteristicType) -> i32 { + match self { + Sword => { + if let Skill(_) = &in_type { + 4 + } else { + 0 + } + } + Lance => match in_type { + Address(_) => 1, + Skill(_) => 3, + _ => 0, + }, + Morgenstern => match in_type { + Stamina(_) | Skill(_) => 1, + _ => 0, + }, + Bow => match in_type { + Address(_) => 1, + Skill(_) => 3, + _ => 0, + }, + } + } +} + +impl GenericObject for Equipments { + fn add_armor(&self) -> u32 { + match self { + Equipments::Chainmail => 2, + Equipments::CookingPot => 1, + _ => 0, + } + } + + fn add_materiel(&self, in_type: &CharacteristicType) -> i32 { + match self { + Equipments::Chainmail => match in_type { + Address(_) | Skill(_) => -1, + Stamina(_) => 1, + _ => 0, + }, + Equipments::CookingPot => { + if let Stamina(_) = in_type { + 2 + } else { + 0 + } + } + Equipments::PamphletTourist => { + if let Luck(_) = in_type { + 4 + } else { + 0 + } + } + Equipments::MedicKit => { + if let Luck(_) = in_type { + 1 + } else { + 0 + } + } + } + } +} + +impl GenericObject for Tools { + fn add_critique(&self) -> u32 { + if let Tools::Dagger = &self { + 6 + } else { + 0 + } + } + + fn add_materiel(&self, in_type: &CharacteristicType) -> i32 { + match self { + Tools::Fourche => match in_type { + Stamina(_) => 3, + Skill(_) => 1, + _ => 0, + }, + Tools::Dagger => { + if let Skill(_) = in_type { + 1 + } else { + 0 + } + } + Tools::RockClimbingKit => { + if let Address(_) = in_type { + 1 + } else { + 0 + } + } + Tools::SackOfGrain => match in_type { + Stamina(_) | Luck(_) => 2, + _ => 0, + }, + } + } +} + +impl GenericObject for Objects { + fn add_armor(&self) -> u32 { + todo!() + } + + fn add_critique(&self) -> u32 { + match self { + Objects::Weapons(a) => a.add_critique(), + Objects::Equipments(a) => a.add_critique(), + Objects::Tools(a) => a.add_critique(), + } + } + + fn add_damage(&self) -> u32 { + match self { + Objects::Weapons(a) => a.add_damage(), + Objects::Equipments(a) => a.add_damage(), + Objects::Tools(a) => a.add_damage(), + } + } + + fn add_materiel(&self, in_type: &CharacteristicType) -> i32 { + match self { + Objects::Weapons(a) => a.add_materiel(in_type), + Objects::Equipments(a) => a.add_materiel(in_type), + Objects::Tools(a) => a.add_materiel(in_type), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 8d3728f..eea7074 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ +pub mod billy_objects; pub mod gui; pub mod sheet; diff --git a/src/sheet.rs b/src/sheet.rs index 577dce5..1779c0a 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -14,7 +14,7 @@ pub enum Classe { } #[derive(Debug, Serialize, Deserialize)] -enum CharacteristicType { +pub enum CharacteristicType { Address(Characteristic), Stamina(Characteristic), Luck(Characteristic), From 27868c7f1fda4d42b5dadf038189d6488bb8a666 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Thu, 5 Feb 2026 18:51:04 +0100 Subject: [PATCH 5/8] Adding _mut methods to change base, carac and materiel fields --- src/sheet.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 8 deletions(-) diff --git a/src/sheet.rs b/src/sheet.rs index 1779c0a..c8085d8 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -57,6 +57,13 @@ impl CharacterSheet { unreachable!() } } + fn address_mut(&mut self) -> &mut Characteristic { + if let CharacteristicType::Address(addr) = &mut self.address { + addr + } else { + unreachable!() + } + } pub fn stamina(&self) -> &Characteristic { if let CharacteristicType::Stamina(sta) = &self.stamina { sta @@ -64,6 +71,13 @@ impl CharacterSheet { unreachable!() } } + fn stamina_mut(&mut self) -> &mut Characteristic { + if let CharacteristicType::Stamina(sta) = &mut self.stamina { + sta + } else { + unreachable!() + } + } pub fn luck(&self) -> &Characteristic { if let CharacteristicType::Luck(luck) = &self.luck { luck @@ -71,6 +85,13 @@ impl CharacterSheet { unreachable!() } } + fn luck_mut(&mut self) -> &mut Characteristic { + if let CharacteristicType::Luck(luck) = &mut self.luck { + luck + } else { + unreachable!() + } + } pub fn skill(&self) -> &Characteristic { if let CharacteristicType::Skill(sk) = &self.skill { sk @@ -78,6 +99,14 @@ impl CharacterSheet { unreachable!() } } + + fn skill_mut(&mut self) -> &mut Characteristic { + if let CharacteristicType::Skill(sk) = &mut self.skill { + sk + } else { + unreachable!() + } + } pub fn health(&self) -> u32 { self.health } @@ -95,6 +124,17 @@ impl CharacterSheet { } } +impl CharacteristicType { + fn check(&self) { + match self { + CharacteristicType::Address(_) => println!("Rules for address"), + CharacteristicType::Stamina(_) => println!("Rules for stamina"), + CharacteristicType::Luck(_) => println!("Rules for luck"), + CharacteristicType::Skill(_) => println!("Rules for skill"), + } + } +} + impl SheetGui for CharacterSheet { fn shortcut( &self, @@ -123,27 +163,39 @@ impl SheetGui for CharacterSheet { fn gui_address(&mut self, ui: &mut Ui) { let workaround = self as &CharacterSheet; - (self.address.base, self.address.carac, self.address.materiel) = - self.shortcut(ui, "Adresse", workaround.address()); + ( + self.address_mut().base, + self.address_mut().carac, + self.address_mut().materiel, + ) = self.shortcut(ui, "Adresse", workaround.address()); ui.label("Ne peut dépasser 5"); } fn gui_stamina(&mut self, ui: &mut Ui) { let workaround = self as &CharacterSheet; - (self.stamina.base, self.stamina.carac, self.stamina.materiel) = - self.shortcut(ui, "Endurance", workaround.stamina()); + ( + self.stamina_mut().base, + self.stamina_mut().carac, + self.stamina_mut().materiel, + ) = self.shortcut(ui, "Endurance", workaround.stamina()); } fn gui_luck(&mut self, ui: &mut Ui) { let workaround = self as &CharacterSheet; - (self.luck.base, self.luck.carac, self.luck.materiel) = - self.shortcut(ui, "Chance", workaround.luck()); + ( + self.luck_mut().base, + self.luck_mut().carac, + self.luck_mut().materiel, + ) = self.shortcut(ui, "Chance", workaround.luck()); } fn gui_skill(&mut self, ui: &mut Ui) { let workaround = self as &CharacterSheet; - (self.skill.base, self.skill.carac, self.skill.materiel) = - self.shortcut(ui, "Habileté", workaround.skill()); + ( + self.skill_mut().base, + self.skill_mut().carac, + self.skill_mut().materiel, + ) = self.shortcut(ui, "Habileté", workaround.skill()); } fn secondary_stats(&mut self, ui: &mut Ui) { @@ -162,6 +214,8 @@ impl SheetGui for CharacterSheet { ui.add(DragValue::new(&mut armor)); }); ui.label("Critique"); + self.damage = damage; + self.armor = armor; } } From ad0ffc4cd9404c69e3dd3b2590a7f81a519b61ed Mon Sep 17 00:00:00 2001 From: Pcornat Date: Thu, 5 Feb 2026 18:51:14 +0100 Subject: [PATCH 6/8] Fix values for Address charac --- src/sheet.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sheet.rs b/src/sheet.rs index c8085d8..5bb3ff1 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -233,10 +233,10 @@ impl Default for CharacterSheet { character_class: Classe::Warrior, character: "Billy".to_string(), address: CharacteristicType::Address(Characteristic { - base: 0, + base: 1, carac: 0, materiel: 0, - additional: 1, + additional: 0, }), stamina: CharacteristicType::Stamina(Characteristic { base: 2, From c6fedb7b910de8cf61958884c71298677b011413 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Thu, 12 Feb 2026 20:38:17 +0100 Subject: [PATCH 7/8] Dealing with objects: it seems done. --- src/billy_objects.rs | 14 ++++-- src/sheet.rs | 107 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/src/billy_objects.rs b/src/billy_objects.rs index f133028..b422b43 100644 --- a/src/billy_objects.rs +++ b/src/billy_objects.rs @@ -16,7 +16,7 @@ pub trait GenericObject { fn add_materiel(&self, in_type: &CharacteristicType) -> i32; } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Clone)] pub enum Weapons { Sword, Lance, @@ -24,7 +24,7 @@ pub enum Weapons { Bow, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Clone)] pub enum Equipments { Chainmail, CookingPot, @@ -32,7 +32,7 @@ pub enum Equipments { MedicKit, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Clone)] pub enum Tools { Fourche, Dagger, @@ -40,7 +40,7 @@ pub enum Tools { SackOfGrain, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Hash, Eq, PartialEq, Clone)] pub enum Objects { Weapons(Weapons), Equipments(Equipments), @@ -164,7 +164,11 @@ impl GenericObject for Tools { impl GenericObject for Objects { fn add_armor(&self) -> u32 { - todo!() + match self { + Objects::Weapons(a) => a.add_armor(), + Objects::Equipments(a) => a.add_armor(), + Objects::Tools(a) => a.add_armor(), + } } fn add_critique(&self) -> u32 { diff --git a/src/sheet.rs b/src/sheet.rs index 5bb3ff1..5c924e8 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -1,9 +1,26 @@ -use eframe::egui::widgets::DragValue; -use eframe::egui::Ui; +use crate::billy_objects::{Equipments::*, GenericObject, Objects, Tools::*, Weapons::*}; +use crate::gui::SheetGui; +use eframe::egui::{widgets::DragValue, Ui}; use serde::{Deserialize, Serialize}; +use std::collections::hash_set; use std::io::Write as _; -use crate::gui::SheetGui; +const ALL_OBJECTS: [Objects; 12] = [ + Objects::Weapons(Sword), + Objects::Weapons(Lance), + Objects::Weapons(Morgenstern), + Objects::Weapons(Bow), + Objects::Equipments(Chainmail), + Objects::Equipments(CookingPot), + Objects::Equipments(PamphletTourist), + Objects::Equipments(MedicKit), + Objects::Tools(Fourche), + Objects::Tools(Dagger), + Objects::Tools(RockClimbingKit), + Objects::Tools(SackOfGrain), +]; + +const MAX_OBJ: usize = 3; #[derive(Debug, Serialize, Deserialize)] pub enum Classe { @@ -30,11 +47,90 @@ pub struct CharacterSheet { stamina: CharacteristicType, luck: CharacteristicType, skill: CharacteristicType, + objects: hash_set::HashSet, health: u32, armor: u32, damage: u32, glory: u32, money: u32, + critique: u32, + nb_weapons: u8, + nb_equipments: u8, + nb_tools: u8, +} + +#[derive(Debug)] +pub struct SheetRuler { + pub available_objects: hash_set::HashSet, +} + +impl Default for SheetRuler { + fn default() -> Self { + Self { + available_objects: hash_set::HashSet::from_iter(ALL_OBJECTS), + } + } +} + +impl SheetRuler { + fn change_carac( + object: &Objects, + sheet: &mut CharacterSheet, + operation: impl Fn(u32, i32) -> u32, + ) { + sheet.address_mut().materiel = operation( + sheet.address_mut().materiel, + object.add_materiel(&sheet.address), + ); + sheet.skill_mut().materiel = operation( + sheet.skill_mut().materiel, + object.add_materiel(&sheet.skill), + ); + sheet.luck_mut().materiel = + operation(sheet.luck_mut().materiel, object.add_materiel(&sheet.luck)); + sheet.stamina_mut().materiel = operation( + sheet.stamina_mut().materiel, + object.add_materiel(&sheet.stamina), + ); + sheet.armor = operation(sheet.armor, object.add_armor() as i32); + sheet.damage = operation(sheet.armor, object.add_damage() as i32); + sheet.critique = operation(sheet.critique, object.add_critique() as i32); + } + pub fn insert_object(&mut self, sheet: &mut CharacterSheet, object: Objects) -> bool { + if self.available_objects.len() >= MAX_OBJ || sheet.objects.contains(&object) { + false + } else { + Self::change_carac(&object, sheet, |a, b| a + b as u32); + let remove = self.available_objects.remove(&object); + let r = sheet.objects.insert(object.clone()) && remove; + if r { + match object { + Objects::Weapons(_) => sheet.nb_weapons += 1, + Objects::Equipments(_) => sheet.nb_equipments += 1, + Objects::Tools(_) => sheet.nb_tools += 1, + } + } + r + } + } + + pub fn erase_object(&mut self, sheet: &mut CharacterSheet, object: Objects) -> bool { + if sheet.objects.contains(&object) { + Self::change_carac(&object, sheet, |a, b| a - b as u32); + let remove = sheet.objects.remove(&object); + let r = self.available_objects.insert(object.clone()) && remove; + if r { + match object { + Objects::Weapons(_) => sheet.nb_weapons -= 1, + Objects::Equipments(_) => sheet.nb_equipments -= 1, + Objects::Tools(_) => sheet.nb_tools -= 1, + } + } + r + } else { + false + } + } } pub fn write_sheet(path: &std::path::Path, sheet: &CharacterSheet) -> std::io::Result<()> { @@ -256,11 +352,16 @@ impl Default for CharacterSheet { materiel: 0, additional: 0, }), + objects: hash_set::HashSet::default(), health: 0, armor: 0, damage: 0, glory: 0, money: 0, + critique: 0, + nb_weapons: 0, + nb_equipments: 0, + nb_tools: 0, } } } From 3f39a3dcc3d67566b9261885566c6d7a9d2f7e3c Mon Sep 17 00:00:00 2001 From: Pcornat Date: Thu, 12 Feb 2026 20:38:27 +0100 Subject: [PATCH 8/8] Replace println! by todo! --- src/sheet.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sheet.rs b/src/sheet.rs index 5c924e8..b5c1cf0 100644 --- a/src/sheet.rs +++ b/src/sheet.rs @@ -223,10 +223,10 @@ impl CharacterSheet { impl CharacteristicType { fn check(&self) { match self { - CharacteristicType::Address(_) => println!("Rules for address"), - CharacteristicType::Stamina(_) => println!("Rules for stamina"), - CharacteristicType::Luck(_) => println!("Rules for luck"), - CharacteristicType::Skill(_) => println!("Rules for skill"), + CharacteristicType::Address(_) => todo!("Rules for address"), + CharacteristicType::Stamina(_) => todo!("Rules for stamina"), + CharacteristicType::Luck(_) => todo!("Rules for luck"), + CharacteristicType::Skill(_) => todo!("Rules for skill"), } } }