/** * Guarda el Token y envía un correo de confirmación. * * Usa el separador: ¬ * * @param type string $token Formato: '<md5>¬<email>' * @return type bool */ private function setToken($token) { if (count($tmp = explode('¬', $token)) > 1) { $email = $tmp[1]; if (Check::mail($email)) { // Obtenemos la plantilla para asunto y contenido $template = Template::get(7); // Sustituimos los datos $subject = $template->title; // En el contenido: $search = array('%USERNAME%', '%CHANGEURL%'); $replace = array($this->name, SITE_URL . '/user/changeemail/' . base64_encode($token)); $content = \str_replace($search, $replace, $template->text); $mail = new Mail(); $mail->to = $email; $mail->toName = $this->name; $mail->subject = $subject; $mail->content = $content; $mail->html = true; $mail->template = $template->id; $mail->send(); return self::query('UPDATE user SET token = :token WHERE id = :id', array(':id' => $this->id, ':token' => $token)); } } }
private function process_userPersonal(&$project, &$errors) { if (!isset($_POST['process_userPersonal'])) { return false; } // campos que guarda este paso $fields = array('contract_name', 'contract_nif', 'contract_email', 'phone', 'contract_birthdate', 'address', 'zipcode', 'location', 'country'); $personalData = array(); foreach ($fields as $field) { if (isset($_POST[$field])) { $project->{$field} = $_POST[$field]; $personalData[$field] = $_POST[$field]; } } if (!$_POST['secondary_address']) { $project->post_address = null; $project->post_zipcode = null; $project->post_location = null; $project->post_country = null; } // actualizamos estos datos en los personales del usuario if (!empty($personalData)) { Model\User::setPersonal($project->owner, $personalData, true); } // cuentas bancarias $ppacc = !empty($_POST['paypal']) ? $_POST['paypal'] : ''; $bankacc = !empty($_POST['bank']) ? $_POST['bank'] : ''; // primero checkeamos si la cuenta Paypal es tipo email if (!Check::mail($ppacc)) { $project->errors['userPersonal']['paypal'] = Text::get('validate-project-paypal_account'); } else { $project->okeys['userPersonal']['paypal'] = true; } $accounts = Model\Project\Account::get($project->id); $accounts->paypal = $ppacc; $accounts->bank = $bankacc; $accounts->save($project->errors['userPersonal']); return true; }
/** * Modificación perfil de usuario. * Metodo Obsoleto porque esto lo hacen en el dashboard */ public function edit() { $user = $_SESSION['user']; if ($_SERVER['REQUEST_METHOD'] == 'POST') { $errors = array(); // E-mail if ($_POST['change_email']) { if (empty($_POST['user_nemail'])) { $errors['email'] = Text::get('error-user-email-empty'); } elseif (!\Goteo\Library\Check::mail($_POST['user_nemail'])) { $errors['email'] = Text::get('error-user-email-invalid'); } elseif (empty($_POST['user_remail'])) { $errors['email']['retry'] = Text::get('error-user-email-empty'); } elseif (strcmp($_POST['user_nemail'], $_POST['user_remail']) !== 0) { $errors['email']['retry'] = Text::get('error-user-email-confirm'); } else { $user->email = $_POST['user_nemail']; } } // Contraseña if ($_POST['change_password']) { /* * Quitamos esta verificacion porque los usuarios que acceden mediante servicio no tienen contraseña * if(empty($_POST['user_password'])) { $errors['password'] = Text::get('error-user-password-empty'); } else */ if (!Model\User::login($user->id, $_POST['user_password'])) { $errors['password'] = Text::get('error-user-wrong-password'); } elseif (empty($_POST['user_npassword'])) { $errors['password']['new'] = Text::get('error-user-password-empty'); } elseif (!\Goteo\Library\Check::password($_POST['user_npassword'])) { $errors['password']['new'] = Text::get('error-user-password-invalid'); } elseif (empty($_POST['user_rpassword'])) { $errors['password']['retry'] = Text::get('error-user-password-empty'); } elseif (strcmp($_POST['user_npassword'], $_POST['user_rpassword']) !== 0) { $errors['password']['retry'] = Text::get('error-user-password-confirm'); } else { $user->password = $_POST['user_npassword']; } } // Avatar if (!empty($_FILES['user_avatar']['name'])) { $user->avatar = $_FILES['user_avatar']; } // tratar si quitan la imagen if (!empty($_POST['avatar-' . $user->avatar->id . '-remove'])) { $user->avatar->remove('user'); $user->avatar = ''; } // Perfil público $user->name = $_POST['user_name']; $user->about = $_POST['user_about']; $user->keywords = $_POST['user_keywords']; $user->contribution = $_POST['user_contribution']; $user->twitter = $_POST['user_twitter']; $user->facebook = $_POST['user_facebook']; $user->linkedin = $_POST['user_linkedin']; // Intereses $user->interests = $_POST['user_interests']; // Páginas Web if (!empty($_POST['user_webs']['remove'])) { $user->webs = array('remove' => $_POST['user_webs']['remove']); } elseif (!empty($_POST['user_webs']['add']) && !empty($_POST['user_webs']['add'][0])) { $user->webs = array('add' => $_POST['user_webs']['add']); } else { $user->webs = array('edit', $_POST['user_webs']['edit']); } if ($user->save($errors)) { // Refresca la sesión. $user = Model\User::flush(); if (isset($_POST['save'])) { throw new Redirection('/dashboard'); } else { throw new Redirection('/user/edit'); } } } return new View('view/user/edit.html.php', array('user' => $user, 'errors' => $errors)); }
/** * Cambio de email / contraseña * * @param object $user instancia de Model\User (por referencia) * @param array $errors (por referencia) * @param string $log_action (por referencia) * @return boolean si se guarda bien */ public static function process_access(&$user, &$errors, &$log_action) { // E-mail if (!empty($_POST['user_nemail']) || !empty($_POST['user_remail'])) { if (empty($_POST['user_nemail'])) { $errors['email'] = Text::get('error-user-email-empty'); } elseif (!\Goteo\Library\Check::mail($_POST['user_nemail'])) { $errors['email'] = Text::get('error-user-email-invalid'); } elseif (empty($_POST['user_remail'])) { $errors['email_retry'] = Text::get('error-user-email-empty'); } elseif (strcmp($_POST['user_nemail'], $_POST['user_remail']) !== 0) { $errors['email_retry'] = Text::get('error-user-email-confirm'); } else { $user->email = $_POST['user_nemail']; unset($_POST['user_nemail']); unset($_POST['user_remail']); Message::Info(Text::get('user-email-change-sended')); $log_action = 'Cambiado su email'; //feed admin } } // Contraseña if (!empty($_POST['user_npassword']) || !empty($_POST['user_rpassword'])) { // No verificamos la contraseña actual (ni en recover ni en normal) porque los usuarios que acceden mediante servicio no tienen contraseña if (empty($_POST['user_npassword'])) { $errors['password_new'] = Text::get('error-user-password-empty'); } elseif (!\Goteo\Library\Check::password($_POST['user_npassword'])) { $errors['password_new'] = Text::get('error-user-password-invalid'); } elseif (empty($_POST['user_rpassword'])) { $errors['password_retry'] = Text::get('error-user-password-empty'); } elseif (strcmp($_POST['user_npassword'], $_POST['user_rpassword']) !== 0) { $errors['password_retry'] = Text::get('error-user-password-confirm'); } else { $user->password = $_POST['user_npassword']; unset($_POST['user_password']); unset($_POST['user_npassword']); unset($_POST['user_rpassword']); Message::Info(Text::get('user-password-changed')); $log_action = 'Cambiado su contraseña'; //feed admin } } if (empty($errors) && $user->save($errors)) { // Refresca la sesión. $user = Model\User::flush(); if (isset($_SESSION['recovering'])) { unset($_SESSION['recovering']); } return true; } else { Message::Error(Text::get('user-save-fail')); $log_action = '¡ERROR! al cambiar email/contraseña'; //feed admin return false; } }
public function index() { $page = Page::get('contact'); $errors = array(); if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['send'])) { // verificamos referer $URL = NODE_ID != GOTEO_NODE ? NODE_URL : SITE_URL; $referer = $URL . '/contact'; // verificamos token if (!isset($_POST['msg_token']) || $_POST['msg_token'] != $_SESSION['msg_token'] || $_SERVER['HTTP_REFERER'] != $referer) { header("HTTP/1.1 400 Bad request"); die('Token incorrect'); } $name = $_POST['name']; // si falta mensaje, email o asunto, error if (empty($_POST['email'])) { $errors['email'] = Text::get('error-contact-email-empty'); } elseif (!\Goteo\Library\Check::mail($_POST['email'])) { $errors['email'] = Text::get('error-contact-email-invalid'); } else { $email = $_POST['email']; } if (empty($_POST['subject'])) { $errors['subject'] = Text::get('error-contact-subject-empty'); } else { $subject = $_POST['subject']; } if (empty($_POST['message'])) { $errors['message'] = Text::get('error-contact-message-empty'); } else { $msg_content = nl2br(\strip_tags($_POST['message'])); } // verificamos el captcha require 'library/recaptchalib.php'; $resp = recaptcha_check_answer(RECAPTCHA_PRIVATE_KEY, $_SERVER["REMOTE_ADDR"], $_POST["recaptcha_challenge_field"], $_POST["recaptcha_response"]); if (!$resp->is_valid) { $errors['recaptcha'] = Text::get('error-contact-captcha'); } $data = array('subject' => $_POST['subject'], 'name' => $_POST['name'], 'email' => $_POST['email'], 'message' => $_POST['message']); if (empty($errors)) { // Obtenemos la plantilla para asunto y contenido $template = Template::get(1); // Sustituimos los datos $subject = str_replace('%SUBJECT%', $subject, $template->title); $to = \GOTEO_CONTACT_MAIL; $toName = \GOTEO_MAIL_NAME; // En el contenido: $search = array('%TONAME%', '%MESSAGE%', '%USEREMAIL%'); $replace = array($toName, $msg_content, $email); $content = \str_replace($search, $replace, $template->text); $mailHandler = new Mail(); $mailHandler->to = $to; $mailHandler->toName = $toName; $mailHandler->subject = $subject; $mailHandler->content = $content; $mailHandler->reply = $email; $mailHandler->html = true; $mailHandler->template = $template->id; if ($mailHandler->send($errors)) { Message::Info('Mensaje de contacto enviado correctamente.'); $data = array(); } else { Message::Error('Ha fallado al enviar el mensaje.'); } unset($mailHandler); } } return new View('view/about/contact.html.php', array('data' => $data, 'errors' => $errors)); }
public function check() { $errors =& $this->errors; $okeys =& $this->okeys; // reseteamos la puntuación $this->setScore(0, 0, true); /***************** Revisión de campos del paso 1, PERFIL *****************/ $score = 0; // obligatorios: nombre, email, ciudad if (empty($this->user->name)) { $errors['userProfile']['name'] = Text::get('validate-user-field-name'); } else { $okeys['userProfile']['name'] = 'ok'; $score += 2; } // se supone que tiene email porque sino no puede tener usuario, no? if (!empty($this->user->email)) { ++$score; } if (empty($this->user->location)) { $errors['userProfile']['location'] = Text::get('validate-user-field-location'); } else { $okeys['userProfile']['location'] = 'ok'; ++$score; } if (!empty($this->user->avatar) && $this->user->avatar->id != 1) { $okeys['userProfile']['avatar'] = empty($errors['userProfile']['avatar']) ? 'ok' : null; $score += 2; } if (!empty($this->user->about)) { $okeys['userProfile']['about'] = 'ok'; ++$score; // otro +1 si tiene más de 1000 caracteres (pero menos de 2000) if (\strlen($this->user->about) > 1000 && \strlen($this->user->about) < 2000) { ++$score; } } else { $errors['userProfile']['about'] = Text::get('validate-user-field-about'); } if (!empty($this->user->interests)) { $okeys['userProfile']['interests'] = 'ok'; ++$score; } if (empty($this->user->webs)) { $errors['userProfile']['webs'] = Text::get('validate-project-userProfile-web'); } else { $okeys['userProfile']['webs'] = 'ok'; ++$score; //if (count($this->user->webs) > 2) ++$score; $anyerror = false; foreach ($this->user->webs as $web) { if (trim(str_replace('http://', '', $web->url)) == '') { $anyerror = !$anyerror ?: true; $errors['userProfile']['web-' . $web->id . '-url'] = Text::get('validate-user-field-web'); } else { $okeys['userProfile']['web-' . $web->id . '-url'] = 'ok'; } } if ($anyerror) { unset($okeys['userProfile']['webs']); $errors['userProfile']['webs'] = Text::get('validate-project-userProfile-any_error'); } } if (!empty($this->user->facebook)) { $okeys['userProfile']['facebook'] = 'ok'; } if (!empty($this->user->twitter)) { $okeys['userProfile']['twitter'] = 'ok'; } if (!empty($this->user->linkedin)) { $okeys['userProfile']['linkedin'] = 'ok'; } //puntos $this->setScore($score, 9); // $this->setScore($score, 10); /***************** FIN Revisión del paso 1, PERFIL *****************/ /***************** Revisión de campos del paso 2,DATOS PERSONALES *****************/ $score = 0; // obligatorios: todos if (!empty($this->contract_entity)) { if (empty($this->entity_name)) { $errors['userPersonal']['entity_name'] = Text::get('mandatory-project-field-entity_name'); } else { $okeys['userPersonal']['entity_name'] = 'ok'; } if (empty($this->entity_office)) { $errors['userPersonal']['entity_office'] = Text::get('mandatory-project-field-entity_office'); } else { $okeys['userPersonal']['entity_office'] = 'ok'; } } if (empty($this->contract_name)) { $errors['userPersonal']['contract_name'] = Text::get('mandatory-project-field-contract_name'); } else { $okeys['userPersonal']['contract_name'] = 'ok'; ++$score; } if (empty($this->contract_email)) { $errors['userPersonal']['contract_email'] = Text::get('mandatory-project-field-contract_email'); } elseif (!Check::mail($this->contract_email)) { $errors['userPersonal']['contract_email'] = Text::get('validate-project-value-contract_email'); } else { $okeys['userPersonal']['contract_email'] = 'ok'; ++$score; } if (empty($this->contract_birthdate)) { $errors['userPersonal']['contract_birthdate'] = Text::get('mandatory-project-field-contract_birthdate'); } else { $okeys['userPersonal']['contract_birthdate'] = 'ok'; ++$score; } if (empty($this->phone)) { $errors['userPersonal']['phone'] = Text::get('mandatory-project-field-phone'); } elseif (!Check::phone($this->phone)) { $errors['userPersonal']['phone'] = Text::get('validate-project-value-phone'); } else { $okeys['userPersonal']['phone'] = 'ok'; ++$score; } if (empty($this->address)) { $errors['userPersonal']['address'] = Text::get('mandatory-project-field-address'); } else { $okeys['userPersonal']['address'] = 'ok'; ++$score; } if (empty($this->zipcode)) { $errors['userPersonal']['zipcode'] = Text::get('mandatory-project-field-zipcode'); } else { $okeys['userPersonal']['zipcode'] = 'ok'; ++$score; } /*if (empty($this->location)) { $errors['userPersonal']['location'] = Text::get('mandatory-project-field-residence'); } else { $okeys['userPersonal']['location'] = 'ok'; ++$score; }*/ if (empty($this->country)) { $errors['userPersonal']['country'] = Text::get('mandatory-project-field-country'); } else { $okeys['userPersonal']['country'] = 'ok'; ++$score; } $this->setScore($score, 7); /***************** FIN Revisión del paso 2, DATOS PERSONALES *****************/ /***************** Revisión de campos del paso 3, DESCRIPCION *****************/ $score = 0; // obligatorios: nombre, subtitulo, imagen, descripcion, about, motivation, categorias, video, localización if (empty($this->name)) { $errors['overview']['name'] = Text::get('mandatory-project-field-name'); } else { $okeys['overview']['name'] = 'ok'; $score += 3; } if (!empty($this->subtitle)) { $okeys['overview']['subtitle'] = 'ok'; } if (empty($this->gallery) && empty($errors['overview']['image'])) { $errors['overview']['image'] .= Text::get('mandatory-project-field-image'); } else { $okeys['overview']['image'] = empty($errors['overview']['image']) ? 'ok' : null; $score += 3; if (count($this->gallery) >= 2) { ++$score; } } if (empty($this->description)) { $errors['overview']['description'] = Text::get('mandatory-project-field-description'); /* } elseif (!Check::words($this->description, 80)) { $errors['overview']['description'] = Text::get('validate-project-field-description');*/ } else { $okeys['overview']['description'] = 'ok'; $score += 2; } // if (empty($this->about)) { // $errors['overview']['about'] = Text::get('mandatory-project-field-about'); // } else { $okeys['overview']['about'] = 'ok'; ++$score; // } if (empty($this->motivation)) { $errors['overview']['motivation'] = Text::get('mandatory-project-field-motivation'); } else { $okeys['overview']['motivation'] = 'ok'; ++$score; } if (!empty($this->goal)) { $okeys['overview']['goal'] = 'ok'; ++$score; } if (!empty($this->related)) { $okeys['overview']['related'] = 'ok'; ++$score; } if (empty($this->categories)) { $errors['overview']['categories'] = Text::get('mandatory-project-field-category'); } else { $okeys['overview']['categories'] = 'ok'; ++$score; } if (empty($this->project_location)) { $errors['overview']['project_location'] = Text::get('mandatory-project-field-location'); } else { $okeys['overview']['project_location'] = 'ok'; ++$score; } $this->setScore($score, 6); // $this->setScore($score, 15); /***************** FIN Revisión del paso 3, DESCRIPCION *****************/ /***************** Revisión de campos del paso 4, COSTES *****************/ $score = 0; $scoreName = $scoreDesc = $scoreAmount = $scoreDate = 0; if (count($this->costs) < 2) { $errors['costs']['costs'] = Text::get('mandatory-project-costs'); } else { $okeys['costs']['costs'] = 'ok'; $score += 2; } $anyerror = false; foreach ($this->costs as $cost) { if (empty($cost->cost)) { $errors['costs']['cost-' . $cost->id . '-cost'] = Text::get('mandatory-cost-field-name'); $anyerror = !$anyerror ?: true; } else { $okeys['costs']['cost-' . $cost->id . '-cost'] = 'ok'; $scoreName = 1; } if (empty($cost->type)) { $errors['costs']['cost-' . $cost->id . '-type'] = Text::get('mandatory-cost-field-type'); $anyerror = !$anyerror ?: true; } else { $okeys['costs']['cost-' . $cost->id . '-type'] = 'ok'; } if (empty($cost->description)) { $errors['costs']['cost-' . $cost->id . '-description'] = Text::get('mandatory-cost-field-description'); $anyerror = !$anyerror ?: true; } else { $okeys['costs']['cost-' . $cost->id . '-description'] = 'ok'; $scoreDesc = 1; } if (empty($cost->amount)) { $errors['costs']['cost-' . $cost->id . '-amount'] = Text::get('mandatory-cost-field-amount'); $anyerror = !$anyerror ?: true; } else { $okeys['costs']['cost-' . $cost->id . '-amount'] = 'ok'; $scoreAmount = 1; } if ($cost->type == 'task' && (empty($cost->from) || empty($cost->until))) { $errors['costs']['cost-' . $cost->id . '-dates'] = Text::get('mandatory-cost-field-task_dates'); $anyerror = !$anyerror ?: true; } elseif ($cost->type == 'task') { $okeys['costs']['cost-' . $cost->id . '-dates'] = 'ok'; $scoreDate = 1; } } if ($anyerror) { unset($okeys['costs']['costs']); $errors['costs']['costs'] = Text::get('validate-project-costs-any_error'); } $score = $score + $scoreName + $scoreDesc + $scoreAmount + $scoreDate; $costdif = $this->maxcost - $this->mincost; $maxdif = $this->mincost * 0.5; $scoredif = $this->mincost * 0.35; if ($this->mincost == 0) { $errors['costs']['total-costs'] = Text::get('mandatory-project-total-costs'); } elseif ($costdif > $maxdif) { $errors['costs']['total-costs'] = Text::get('validate-project-total-costs'); } else { $okeys['costs']['total-costs'] = 'ok'; } if ($costdif <= $scoredif) { ++$score; } $this->setScore($score, 7); /***************** FIN Revisión del paso 4, COSTES *****************/ /***************** Revisión de campos del paso 5, RETORNOS *****************/ $score = 0; $scoreName = $scoreDesc = $scoreAmount = $scoreLicense = 0; if (empty($this->social_rewards)) { $errors['rewards']['social_rewards'] = Text::get('validate-project-social_rewards'); } else { $okeys['rewards']['social_rewards'] = 'ok'; if (count($this->social_rewards) >= 2) { $score += 2; } } if (empty($this->individual_rewards)) { $errors['rewards']['individual_rewards'] = Text::get('validate-project-individual_rewards'); } else { $okeys['rewards']['individual_rewards'] = 'ok'; if (count($this->individual_rewards) >= 3) { ++$score; } } $anyerror = false; foreach ($this->social_rewards as $social) { if (empty($social->reward)) { $errors['rewards']['social_reward-' . $social->id . 'reward'] = Text::get('mandatory-social_reward-field-name'); $anyerror = !$anyerror ?: true; } else { $okeys['rewards']['social_reward-' . $social->id . 'reward'] = 'ok'; $scoreName = 1; } if (empty($social->description)) { $errors['rewards']['social_reward-' . $social->id . '-description'] = Text::get('mandatory-social_reward-field-description'); $anyerror = !$anyerror ?: true; } else { $okeys['rewards']['social_reward-' . $social->id . '-description'] = 'ok'; $scoreDesc = 1; } if (empty($social->icon)) { $errors['rewards']['social_reward-' . $social->id . '-icon'] = Text::get('mandatory-social_reward-field-icon'); $anyerror = !$anyerror ?: true; } else { $okeys['rewards']['social_reward-' . $social->id . '-icon'] = 'ok'; } if (!empty($social->license)) { $scoreLicense = 1; } } if ($anyerror) { unset($okeys['rewards']['social_rewards']); $errors['rewards']['social_rewards'] = Text::get('validate-project-social_rewards-any_error'); } $score = $score + $scoreName + $scoreDesc + $scoreLicense; $scoreName = $scoreDesc = $scoreAmount = 0; $anyerror = false; foreach ($this->individual_rewards as $individual) { if (empty($individual->reward)) { $errors['rewards']['individual_reward-' . $individual->id . '-reward'] = Text::get('mandatory-individual_reward-field-name'); $anyerror = !$anyerror ?: true; } else { $okeys['rewards']['individual_reward-' . $individual->id . '-reward'] = 'ok'; $scoreName = 1; } if (empty($individual->description)) { $errors['rewards']['individual_reward-' . $individual->id . '-description'] = Text::get('mandatory-individual_reward-field-description'); $anyerror = !$anyerror ?: true; } else { $okeys['rewards']['individual_reward-' . $individual->id . '-description'] = 'ok'; $scoreDesc = 1; } if (empty($individual->amount)) { $errors['rewards']['individual_reward-' . $individual->id . '-amount'] = Text::get('mandatory-individual_reward-field-amount'); $anyerror = !$anyerror ?: true; } else { $okeys['rewards']['individual_reward-' . $individual->id . '-amount'] = 'ok'; $scoreAmount = 1; } if (empty($individual->icon)) { $errors['rewards']['individual_reward-' . $individual->id . '-icon'] = Text::get('mandatory-individual_reward-field-icon'); $anyerror = !$anyerror ?: true; } else { $okeys['rewards']['individual_reward-' . $individual->id . '-icon'] = 'ok'; } } if ($anyerror) { unset($okeys['rewards']['individual_rewards']); $errors['rewards']['individual_rewards'] = Text::get('validate-project-individual_rewards-any_error'); } $score = $score + $scoreName + $scoreDesc + $scoreAmount; $this->setScore($score, 9); /***************** FIN Revisión del paso 5, RETORNOS *****************/ /***************** Revisión de campos del paso 6, COLABORACIONES *****************/ $scorename = $scoreDesc = 0; $support_type_task = false; foreach ($this->supports as $support) { if (!empty($support->support)) { $okeys['supports']['support-' . $support->id . '-support'] = 'ok'; $scoreName = 1; } if (!empty($support->description)) { $okeys['supports']['support-' . $support->id . '-description'] = 'ok'; $scoreDesc = 1; } if ($support->type == 'task') { $support_type_task = true; } } $score = $scoreName + $scoreDesc; if ($support_type_task) { if (!count($this->skills)) { $errors['supports']['skills'] = Text::get('スキルを選択してください'); } } $this->setScore($score, 2); /***************** FIN Revisión del paso 6, COLABORACIONES *****************/ //-------------- Calculo progreso ---------------------// $this->setProgress(); //-------------- Fin calculo progreso ---------------------// return true; }