diff --git a/.idea/codeception.xml b/.idea/codeception.xml new file mode 100644 index 00000000..ed98e5ee --- /dev/null +++ b/.idea/codeception.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml index ebe16728..d3a7a60e 100755 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -55,6 +55,13 @@ + + + + + + + diff --git a/.idea/phpspec.xml b/.idea/phpspec.xml new file mode 100644 index 00000000..d39fc8c9 --- /dev/null +++ b/.idea/phpspec.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/safekat.iml b/.idea/safekat.iml index 30e3cdd1..0a9466d6 100755 --- a/.idea/safekat.iml +++ b/.idea/safekat.iml @@ -7,6 +7,16 @@ + + + + + + + + + + diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index 4ff6d0ef..b9a084cf 100644 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -97,7 +97,6 @@ $routes->group('configuracion', ['namespace' => 'App\Controllers\Configuracion'] $routes->group('users', ['namespace' => 'App\Controllers\Configuracion'], function ($routes) { $routes->get('', 'Users::index', ['as' => 'userList']); - $routes->get('index', 'Users::index', ['as' => 'userIndex']); $routes->get('list', 'Users::index', ['as' => 'userList2']); $routes->get('add', 'Users::add', ['as' => 'newUser']); $routes->post('add', 'Users::add', ['as' => 'createUser']); diff --git a/ci4/app/Config/Validation.php b/ci4/app/Config/Validation.php index a93a7146..cb05c77a 100755 --- a/ci4/app/Config/Validation.php +++ b/ci4/app/Config/Validation.php @@ -34,7 +34,7 @@ class Validation extends BaseConfig * @var array */ public array $templates = [ - 'list' => 'CodeIgniter\Validation\Views\list', + 'list' => 'CodeIgniter\Validation\Views\list', 'single' => 'CodeIgniter\Validation\Views\single', 'bootstrap_style' => 'themes/_commonPartialsBs/_form_validation_errors', ]; @@ -42,4 +42,6 @@ class Validation extends BaseConfig // -------------------------------------------------------------------- // Rules // -------------------------------------------------------------------- + + } diff --git a/ci4/app/Controllers/Configuracion/Users.php b/ci4/app/Controllers/Configuracion/Users.php index 7e7ab4dc..82cf1422 100755 --- a/ci4/app/Controllers/Configuracion/Users.php +++ b/ci4/app/Controllers/Configuracion/Users.php @@ -20,7 +20,6 @@ class Users extends \App\Controllers\GoBaseController private ChatDeparmentUserModel $chat_department_user_model; - use \CodeIgniter\API\ResponseTrait; protected static $primaryModelName = 'App\Models\UserModel'; @@ -62,7 +61,7 @@ class Users extends \App\Controllers\GoBaseController $this->viewData['usingClientSideDataTable'] = true; $this->viewData['pageSubTitle'] = lang('Basic.global.ManageAllRecords', [lang('Users.user')]); $this->viewData['user_model'] = $this->user_model; - $this->viewData['userList2'] = auth()->getProvider()->findAll(); + $this->viewData['userList2'] = auth()->getProvider()->findAll(); parent::index(); } @@ -77,17 +76,17 @@ class Users extends \App\Controllers\GoBaseController // Obtener contraseña nueva si se ha introducido en texto plano if (empty($postData['new_pwd'])) { $postData['password'] = 'Safekat2024'; // Contraseña por defecto - }else{ + } else { $postData['password'] = $postData['new_pwd']; } + // Obtener los grupos a los que pertenece $currentGroups = $postData['group'] ?? []; $chatDepartments = $postData['chatDepartments'] ?? []; unset($postData['group']); unset($postData['chatDepartments']); - // Generar el nombre de usuario - $postData['username'] = strstr($postData['email'], '@', true); + // Marcar el username como NULL $sanitizedData = $this->sanitized($postData, true); $noException = true; @@ -99,33 +98,43 @@ class Users extends \App\Controllers\GoBaseController if ($this->canValidate()) : try { - $user = new User([ - 'username' => $sanitizedData['username'], - 'first_name' => $sanitizedData['first_name'], - 'last_name' => $sanitizedData['last_name'], - 'email' => $sanitizedData['email'], - 'password' => $sanitizedData['password'], - 'status' => $sanitizedData['status'] ?? 0, - 'active' => $sanitizedData['active'] ?? 0, - ]); - $users->save($user); - $successfulResult = true; // Hacked - } catch (\Exception $e) { - $noException = false; - //$this->dealWithException($e); - if (strpos($e->getMessage(), 'correo duplicado') !== false) { - $this->viewData['errorMessage'] = "El correo electrónico ya está registrado en el sistema"; + // The Email is unique + if ($this->user_model->isEmailUnique($sanitizedData['email'])) { + + // Crear el usuario si pasa la validación + $user = new \CodeIgniter\Shield\Entities\User([ + 'username' => null, // If you don't have a username, be sure to set the value to null anyway, so that it passes CodeIgniter's empty data check + 'first_name' => $sanitizedData['first_name'], + 'last_name' => $sanitizedData['last_name'], + 'cliente_id' => $sanitizedData['cliente_id'], + 'comments' => $sanitizedData['comments'], + 'email' => $sanitizedData['email'], + 'password' => $sanitizedData['password'], + 'status' => $sanitizedData['status'] ?? 0, + 'active' => $sanitizedData['active'] ?? 0, + ]); + // Add the user to the system + $users->save($user); + $successfulResult = true; // Hacked + + } // Email is not unique! + else { + $this->viewData['errorMessage'] = "El correo '". $sanitizedData['email'] ."' ya está registrado en el sistema"; $this->session->setFlashdata('formErrors', $this->model->errors()); + $successfulResult = false; // Hacked } + } catch (\Exception $e) { + $noException = false; + $this->viewData['errorMessage'] = $e->getMessage(); } else: $this->viewData['errorMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Users.user'))]); $this->session->setFlashdata('formErrors', $this->model->errors()); endif; - $thenRedirect = true; // Change this to false if you want your user to stay on the form after submission endif; + if ($noException && $successfulResult) : $id = $users->getInsertID(); @@ -137,12 +146,11 @@ class Users extends \App\Controllers\GoBaseController ]; $this->group_user_model->insert($group_user_data); } - $this->chat_department_user_model->where("user_id",$id)->delete(); - foreach($chatDepartments as $chatDepartment) - { + $this->chat_department_user_model->where("user_id", $id)->delete(); + foreach ($chatDepartments as $chatDepartment) { $this->chat_department_user_model->insert([ "user_id" => $id, - "chat_department_id" => $this->chat_department_model->where("name",$chatDepartment)->first()["id"] + "chat_department_id" => $this->chat_department_model->where("name", $chatDepartment)->first()["id"] ]); } @@ -199,7 +207,6 @@ class Users extends \App\Controllers\GoBaseController unset($postData['group']); unset($postData['chatDepartments']); - // Obtener contraseña nueva si se ha introducido en texto plano // Obtener contraseña nueva si se ha introducido en texto plano if (!empty($postData['new_pwd'])) { $postData['password'] = $postData['new_pwd']; @@ -254,12 +261,11 @@ class Users extends \App\Controllers\GoBaseController ]; $this->group_user_model->insert($group_user_data); } - $this->chat_department_user_model->where("user_id",$id)->delete(); - foreach($chatDepartments as $chatDepartment) - { + $this->chat_department_user_model->where("user_id", $id)->delete(); + foreach ($chatDepartments as $chatDepartment) { $this->chat_department_user_model->insert([ "user_id" => $id, - "chat_department_id" => $this->chat_department_model->where("name",$chatDepartment)->first()["id"] + "chat_department_id" => $this->chat_department_model->where("name", $chatDepartment)->first()["id"] ]); } $id = $user->id ?? $id; @@ -284,7 +290,7 @@ class Users extends \App\Controllers\GoBaseController $this->viewData['formAction'] = route_to('updateUser', $id); $this->viewData['selectedGroups'] = $this->group_model->getUsersRoles($requestedId); $this->viewData['groups'] = $this->group_model->select('keyword, title')->findAll(); - $this->viewData['chatDepartments'] = $this->chat_department_model->select(["display","name","id as chatDepartmentId"])->findAll(); + $this->viewData['chatDepartments'] = $this->chat_department_model->select(["display", "name", "id as chatDepartmentId"])->findAll(); $this->viewData['chatDepartmentUser'] = $this->chat_department_user_model->getChatDepartmentUser($user->id); $this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Users.user') . ' ' . lang('Basic.global.edit3'); @@ -308,7 +314,7 @@ class Users extends \App\Controllers\GoBaseController endif; $users = auth()->getProvider(); - $users->delete($user->id); + $users->delete($user->id, true); $message = "Usuario eliminado correctamente"; return $this->redirect2listView('successMessage', $message); diff --git a/ci4/app/Language/en/Users.php b/ci4/app/Language/en/Users.php index 116d67bc..9ef06c32 100755 --- a/ci4/app/Language/en/Users.php +++ b/ci4/app/Language/en/Users.php @@ -15,7 +15,7 @@ return [ 'createdAt' => 'Created At', 'dateBirth' => 'Date Birth', 'email' => 'Email', - 'emailConfirmed' => 'Email Confirmed', + 'emailConfirmed' => 'Email Confirmed', 'firstName' => 'First Name', 'group' => 'Group', 'idUser' => 'ID User', diff --git a/ci4/app/Models/UserModel.php b/ci4/app/Models/UserModel.php index d397eaf2..5507d64b 100644 --- a/ci4/app/Models/UserModel.php +++ b/ci4/app/Models/UserModel.php @@ -30,7 +30,6 @@ class UserModel extends ShieldUserModel protected $updatedField = 'updated_at'; protected $deletedField = 'deleted_at'; - protected $validationRules = [ "first_name" => "required|trim|max_length[150]", "last_name" => "required|trim|max_length[150]", @@ -77,5 +76,20 @@ class UserModel extends ShieldUserModel } + // Método para comprobar si el email ya está registrado + public function isEmailUnique($email) + { + $builder = $this->db + ->table("auth_identities t1") // La tabla correcta + ->select("t1.secret AS email") + ->where('secret', $email); + + // Obtener resultados + $result = $builder->get()->getRow(); + + // Devuelve true si no se encuentra el correo (es único), false en caso contrario + return $result === null; + } + } diff --git a/ci4/app/Models/Usuarios/UserModel.php b/ci4/app/Models/Usuarios/UserModel.php index 56b34f77..a4748d14 100755 --- a/ci4/app/Models/Usuarios/UserModel.php +++ b/ci4/app/Models/Usuarios/UserModel.php @@ -20,6 +20,7 @@ class UserModel extends \App\Models\BaseModel protected $allowedFields = [ "username", + "email", "first_name", "last_name", "client_id", diff --git a/ci4/app/Views/themes/vuexy/form/user/viewUserForm.php b/ci4/app/Views/themes/vuexy/form/user/viewUserForm.php index 361861c4..88f037ad 100644 --- a/ci4/app/Views/themes/vuexy/form/user/viewUserForm.php +++ b/ci4/app/Views/themes/vuexy/form/user/viewUserForm.php @@ -21,7 +21,7 @@ name="save" value="" > - "btn btn-secondary"]) ?> + "btn btn-secondary"]) ?> diff --git a/ci4/app/Views/themes/vuexy/form/user/viewUserList.php b/ci4/app/Views/themes/vuexy/form/user/viewUserList.php index b22a4c76..b6adb138 100644 --- a/ci4/app/Views/themes/vuexy/form/user/viewUserList.php +++ b/ci4/app/Views/themes/vuexy/form/user/viewUserList.php @@ -1,122 +1,59 @@ -include('themes/_commonPartialsBs/datatables') ?> -extend('themes/vuexy/main/defaultlayout') ?> -section('content'); ?> -
-
+include('themes/_commonPartialsBs/datatables') ?> +extend('themes/vuexy/main/defaultlayout') ?> +section('content'); ?> +
+
-
-
-

- 'btn btn-primary float-end']); ?> -
-
- +
+
+

+ 'btn btn-primary float-end']); ?> +
+
+ - - - - - - - - - - - - - - - - - - - - - */ ?> - - - - - - - - +
- first_name) || strlen($item->first_name) < 51 ? esc($item->first_name) : character_limiter(esc($item->first_name), 50) ?> - - last_name) || strlen($item->last_name) < 51 ? esc($item->last_name) : character_limiter(esc($item->last_name), 50) ?> -
+ + + + + + + + + + + + - + + - - getGroupsTitles($item->token)) || strlen($user_model->getGroupsTitles($item->token)) < 51 ? esc($user_model->getGroupsTitles($item->token)) : character_limiter($user_model->getGroupsTitles($item->token), 50) ?> - + + - - + + +
- email) ? "" : character_limiter(esc(lang($item->email)), 50) ?> + first_name) || strlen($item->first_name) < 51 ? esc($item->first_name) : character_limiter(esc($item->first_name), 50) ?> - last_active) ? '' : date('d/m/Y H:m:s', strtotime($item->last_active)) ?> + + last_name) || strlen($item->last_name) < 51 ? esc($item->last_name) : character_limiter(esc($item->last_name), 50) ?> + + getProvider()->findById($item->id)->email) ? "" : character_limiter(esc(auth()->getProvider()->findById($item->id)->email), 50) ?> + + last_active) ? '' : date('d/m/Y H:m:s', strtotime($item->last_active)) ?> + id), "", ['class' => 'text-body', 'data-id' => $item->id,]); ?> + ", ['class' => 'text-body', 'data-href' => route_to('deleteUser', $item->id), 'data-bs-toggle' => 'modal', 'data-bs-target' => '#confirm2delete']); ?> +
- mobile) || strlen($item->mobile) < 51 ? esc($item->mobile) : character_limiter(esc($item->mobile), 50) ?> - - email) ?> -
+
+ +
+
+
- - id), "", ['class'=>'text-body', 'data-id'=>$item->id,]); ?> - ", ['class'=>'text-body', 'data-href'=>route_to('deleteUser', $item->id), 'data-bs-toggle'=>'modal', 'data-bs-target'=>'#confirm2delete']); ?> - - - - - - -
- -
-
-
- -endSection() ?> \ No newline at end of file +endSection() ?> \ No newline at end of file diff --git a/ci4/composer.lock b/ci4/composer.lock index 30692ee0..1ba99102 100644 --- a/ci4/composer.lock +++ b/ci4/composer.lock @@ -438,33 +438,33 @@ }, { "name": "laminas/laminas-escaper", - "version": "2.13.0", + "version": "2.14.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-escaper.git", - "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba" + "reference": "0f7cb975f4443cf22f33408925c231225cfba8cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/af459883f4018d0f8a0c69c7a209daef3bf973ba", - "reference": "af459883f4018d0f8a0c69c7a209daef3bf973ba", + "url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/0f7cb975f4443cf22f33408925c231225cfba8cb", + "reference": "0f7cb975f4443cf22f33408925c231225cfba8cb", "shasum": "" }, "require": { "ext-ctype": "*", "ext-mbstring": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "conflict": { "zendframework/zend-escaper": "*" }, "require-dev": { - "infection/infection": "^0.27.0", - "laminas/laminas-coding-standard": "~2.5.0", + "infection/infection": "^0.27.9", + "laminas/laminas-coding-standard": "~3.0.0", "maglnet/composer-require-checker": "^3.8.0", - "phpunit/phpunit": "^9.6.7", - "psalm/plugin-phpunit": "^0.18.4", - "vimeo/psalm": "^5.9" + "phpunit/phpunit": "^9.6.16", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.21.1" }, "type": "library", "autoload": { @@ -496,7 +496,7 @@ "type": "community_bridge" } ], - "time": "2023-10-10T08:35:13+00:00" + "time": "2024-10-24T10:12:53+00:00" }, { "name": "masterminds/html5", @@ -986,24 +986,24 @@ }, { "name": "sabberworm/php-css-parser", - "version": "v8.6.0", + "version": "v8.7.0", "source": { "type": "git", "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70" + "reference": "f414ff953002a9b18e3a116f5e462c56f21237cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d2fb94a9641be84d79c7548c6d39bbebba6e9a70", - "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70", + "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/f414ff953002a9b18e3a116f5e462c56f21237cf", + "reference": "f414ff953002a9b18e3a116f5e462c56f21237cf", "shasum": "" }, "require": { "ext-iconv": "*", - "php": ">=5.6.20" + "php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" }, "require-dev": { - "phpunit/phpunit": "^5.7.27" + "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.40" }, "suggest": { "ext-mbstring": "for parsing UTF-8 CSS" @@ -1045,9 +1045,9 @@ ], "support": { "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.6.0" + "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.7.0" }, - "time": "2024-07-01T07:33:21+00:00" + "time": "2024-10-27T17:38:32+00:00" } ], "packages-dev": [ @@ -1123,16 +1123,16 @@ }, { "name": "fakerphp/faker", - "version": "v1.23.1", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/FakerPHP/Faker.git", - "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b" + "reference": "a136842a532bac9ecd8a1c723852b09915d7db50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/bfb4fe148adbf78eff521199619b93a52ae3554b", - "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/a136842a532bac9ecd8a1c723852b09915d7db50", + "reference": "a136842a532bac9ecd8a1c723852b09915d7db50", "shasum": "" }, "require": { @@ -1180,9 +1180,9 @@ ], "support": { "issues": "https://github.com/FakerPHP/Faker/issues", - "source": "https://github.com/FakerPHP/Faker/tree/v1.23.1" + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.0" }, - "time": "2024-01-02T13:46:09+00:00" + "time": "2024-11-07T15:11:20+00:00" }, { "name": "mikey179/vfsstream", @@ -1238,16 +1238,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845", + "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845", "shasum": "" }, "require": { @@ -1286,7 +1286,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1" }, "funding": [ { @@ -1294,20 +1294,20 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2024-11-08T17:47:46+00:00" }, { "name": "nikic/php-parser", - "version": "v5.2.0", + "version": "v5.3.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb" + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", - "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", + "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", "shasum": "" }, "require": { @@ -1350,9 +1350,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.2.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" }, - "time": "2024-09-15T16:40:33+00:00" + "time": "2024-10-08T18:51:32+00:00" }, { "name": "phar-io/manifest", @@ -1793,16 +1793,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.20", + "version": "9.6.21", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "49d7820565836236411f5dc002d16dd689cde42f" + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/49d7820565836236411f5dc002d16dd689cde42f", - "reference": "49d7820565836236411f5dc002d16dd689cde42f", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", "shasum": "" }, "require": { @@ -1817,7 +1817,7 @@ "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.31", + "phpunit/php-code-coverage": "^9.2.32", "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.4", @@ -1876,7 +1876,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" }, "funding": [ { @@ -1892,7 +1892,7 @@ "type": "tidelift" } ], - "time": "2024-07-10T11:45:39+00:00" + "time": "2024-09-19T10:50:18+00:00" }, { "name": "psr/container", @@ -3037,5 +3037,5 @@ "php": "^8.2" }, "platform-dev": [], - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" }