+
+## Sobre El Proyecto
+
+Escritorio|Móvil
+---|---
+![desktop](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/main_img.webp)|![mobile](https://raw.githubusercontent.com/LemmyNet/joinlemmy-site/main/src/assets/images/mobile_pic.webp)
+
+[Lemmy](https://github.com/LemmyNet/lemmy) es similar a sitios como [Menéame](https://www.meneame.net/), [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), o [Hacker News](https://news.ycombinator.com/): te subscribes a los foros que te interesan, publicas enlaces y debates, luego votas y comentas en ellos. Entre bastidores, es muy diferente; cualquiera puede gestionar fácilmente un servidor, y todos estos servidores son federados (piensa en el correo electrónico), y conectados al mismo universo, llamado [Fediverso](https://es.wikipedia.org/wiki/Fediverso).
+
+Para un agregador de enlaces, esto significa que un usuario registrado en un servidor puede suscribirse a los foros de otro servidor, y puede mantener discusiones con usuarios registrados en otros lugares.
+
+El objetivo general es crear una alternativa a reddit y otros agregadores de enlaces, fácilmente auto-hospedada, descentralizada, fuera de su control e intromisión corporativa.
+
+Cada servidor lemmy puede establecer su propia política de moderación; nombrando a los administradores del sitio y a los moderadores de la comunidad para mantener alejados a los trolls, y fomentar un entorno saludable y no tóxico en el que puedan sentirse cómodos contribuyendo.
+
+*Nota: Las APIs WebSocket y HTTP actualmente son inestables*
+
+### ¿Por qué se llama Lemmy?
+
+- Cantante principal de [Motörhead](https://invidio.us/watch?v=pWB5JZRGl0U).
+- El [videojuego de la vieja escuela]().
+- El [Koopa de Super Mario](https://www.mariowiki.com/Lemmy_Koopa).
+- Los [roedores peludos](http://sunchild.fpwc.org/lemming-the-little-giant-of-the-north/).
+
+### Creado Con
+
+- [Rust](https://www.rust-lang.org)
+- [Actix](https://actix.rs/)
+- [Diesel](http://diesel.rs/)
+- [Inferno](https://infernojs.org)
+- [Typescript](https://www.typescriptlang.org/)
+
+# Características
+
+- Código abierto, [Licencia AGPL](/LICENSE).
+- Auto-hospedado, fácil de desplegar (deploy).
+ - Viene con [Docker](#docker) y [Ansible](#ansible).
+- Interfaz limpia y fácil de usar. Apta para dispositivos móviles.
+ - Sólo se requiere como mínimo un nombre de usuario y una contraseñar para inscribirse!
+ - Soporte de avatar de usuario.
+ - Hilos de comentarios actualizados en directo.
+ - Puntuaciones completas de los votos `(+/-)` como en el antiguo reddit.
+ - Temas, incluidos los claros, los oscuros, y los solarizados.
+ - Emojis con soporte de autocompletado. Empieza tecleando `:`
+ - *Ejemplo* `miau :cat:` => `miau 🐈`
+ - Etiquetado de Usuarios con `@`, etiquetado de Comunidades con `!`.
+ - *Ejemplo* `@miguel@lemmy.ml me invitó a la comunidad !gaming@lemmy.ml`
+ - Carga de imágenes integrada tanto en las publicaciones como en los comentarios.
+ - Una publicación puede consistir en un título y cualquier combinación de texto propio, una URL o nada más.
+ - Notificaciones, sobre las respuestas a los comentarios y cuando te etiquetan.
+ - Las notificaciones se pueden enviar por correo electrónico.
+ - Soporte para mensajes privados.
+ - Soporte de i18n / internacionalización.
+ - Fuentes RSS / Atom para Todo `All`, Suscrito `Subscribed`, Bandeja de entrada `inbox`, Usuario `User`, y Comunidad `Community`.
+- Soporte para la publicación cruzada (cross-posting).
+ - **búsqueda de publicaciones similares** al crear una nueva. Ideal para comunidades de preguntas y respuestas.
+- Capacidades de moderación.
+ - Registros públicos de moderación.
+ - Puedes pegar las publicaciones a la parte superior de las comunidades.
+ - Tanto los administradores del sitio, como los moderadores de la comunidad, pueden nombrar a otros moderadores.
+ - Puedes bloquear, eliminar y restaurar publicaciones y comentarios.
+ - Puedes banear y desbanear usuarios de las comunidades y del sitio.
+ - Puedes transferir el sitio y las comunidades a otros.
+- Puedes borrar completamente tus datos, reemplazando todas las publicaciones y comentarios.
+- Soporte para publicaciones y comunidades NSFW.
+- Alto rendimiento.
+ - El servidor está escrito en rust.
+ - El front end está comprimido (gzipped) en `~80kB`.
+ - El front end funciona sin javascript (sólo lectura).
+ - Soporta arm64 / Raspberry Pi.
+
+## Instalación
+
+- [Docker](https://join.lemmy.ml/docs/es/administration/install_docker.html)
+- [Ansible](https://join.lemmy.ml/docs/es/administration/install_ansible.html)
+
+## Proyectos de Lemmy
+
+### Aplicaciones
+
+- [lemmy-ui - La aplicación web oficial para lemmy](https://github.com/LemmyNet/lemmy-ui)
+- [Lemmur - Un cliente móvil para Lemmy (Android, Linux, Windows)](https://github.com/krawieck/lemmur)
+- [Remmel - Una aplicación IOS nativa](https://github.com/uuttff8/Lemmy-iOS)
+
+### Librerías
+
+- [lemmy-js-client](https://github.com/LemmyNet/lemmy-js-client)
+- [Kotlin API ( en desarrollo )](https://github.com/eiknat/lemmy-client)
+- [Dart API client ( en desarrollo )](https://github.com/krawieck/lemmy_api_client)
+
+## Apoyo / Donación
+
+Lemmy es un software libre y de código abierto, lo que significa que no hay publicidad, monetización o capital de riesgo, nunca. Tus donaciones apoyan directamente el desarrollo a tiempo completo del proyecto.
+
+- [Apoya en Liberapay](https://liberapay.com/Lemmy).
+- [Apoya en Patreon](https://www.patreon.com/dessalines).
+- [Apoya en OpenCollective](https://opencollective.com/lemmy).
+- [Lista de patrocinadores](https://join.lemmy.ml/sponsors).
+
+### Crypto
+
+- bitcoin: `1Hefs7miXS5ff5Ck5xvmjKjXf5242KzRtK`
+- ethereum: `0x400c96c96acbC6E7B3B43B1dc1BB446540a88A01`
+- monero: `41taVyY6e1xApqKyMVDRVxJ76sPkfZhALLTjRvVKpaAh2pBd4wv9RgYj1tSPrx8wc6iE1uWUfjtQdTmTy2FGMeChGVKPQuV`
+
+## Contribuir
+
+- [Instrucciones para contribuir](https://join.lemmy.ml/docs/es/contributing/contributing.html)
+- [Desarrollo por Docker](https://join.lemmy.ml/docs/es/contributing/docker_development.html)
+- [Desarrollo Local](https://join.lemmy.ml/docs/es/contributing/local_development.html)
+
+### Traducciones
+
+Si quieres ayudar con la traducción, echa un vistazo a [Weblate](https://weblate.yerbamate.ml/projects/lemmy/). También puedes ayudar [traduciendo la documentación](https://github.com/LemmyNet/lemmy-docs#adding-a-new-language).
+
+## Contacto
+
+- [Mastodon](https://mastodon.social/@LemmyDev)
+- [Matrix](https://matrix.to/#/#lemmy:matrix.org)
+
+## Repositorios del código
+
+- [GitHub](https://github.com/LemmyNet/lemmy)
+- [Gitea](https://yerbamate.ml/LemmyNet/lemmy)
+- [Codeberg](https://codeberg.org/LemmyNet/lemmy)
+
+## Creditos
+
+Logo hecho por Andy Cuccaro (@andycuccaro) bajo la licencia CC-BY-SA 4.0.
From 1ba570092e0043b7516cccbbb5c27451eb1f0e6a Mon Sep 17 00:00:00 2001
From: Dessalines
Date: Thu, 1 Apr 2021 13:30:24 -0400
Subject: [PATCH 03/14] Adding more rust captcha features. Fixes #1248
---
crates/api/src/lib.rs | 60 +++++-------------------------
crates/api/src/local_user.rs | 8 ++--
crates/api_common/src/person.rs | 4 +-
docker/dev/Dockerfile | 3 --
docker/dev/volume_mount.dockerfile | 4 +-
docker/prod/Dockerfile | 3 --
docker/prod/Dockerfile.arm | 4 +-
7 files changed, 18 insertions(+), 68 deletions(-)
diff --git a/crates/api/src/lib.rs b/crates/api/src/lib.rs
index 5dc678be6..c9de749ef 100644
--- a/crates/api/src/lib.rs
+++ b/crates/api/src/lib.rs
@@ -1,9 +1,9 @@
use actix_web::{web, web::Data};
+use captcha::Captcha;
use lemmy_api_common::{comment::*, community::*, person::*, post::*, site::*, websocket::*};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
use serde::Deserialize;
-use std::{env, process::Command};
mod comment;
mod comment_report;
@@ -158,60 +158,23 @@ where
serialize_websocket_message(&op, &res)
}
-pub(crate) fn captcha_espeak_wav_base64(captcha: &str) -> Result {
- let mut built_text = String::new();
+/// Converts the captcha to a base64 encoded wav audio file
+pub(crate) fn captcha_as_wav_base64(captcha: &Captcha) -> String {
+ let letters = captcha.as_wav();
- // Building proper speech text for espeak
- for mut c in captcha.chars() {
- let new_str = if c.is_alphabetic() {
- if c.is_lowercase() {
- c.make_ascii_uppercase();
- format!("lower case {} ... ", c)
- } else {
- c.make_ascii_uppercase();
- format!("capital {} ... ", c)
- }
- } else {
- format!("{} ...", c)
- };
+ let mut concat_letters: Vec = Vec::new();
- built_text.push_str(&new_str);
+ for letter in letters {
+ let bytes = letter.unwrap_or_default();
+ concat_letters.extend(bytes);
}
- espeak_wav_base64(&built_text)
-}
-
-pub(crate) fn espeak_wav_base64(text: &str) -> Result {
- // Make a temp file path
- let uuid = uuid::Uuid::new_v4().to_string();
- let file_path = format!(
- "{}/lemmy_espeak_{}.wav",
- env::temp_dir().to_string_lossy(),
- &uuid
- );
-
- // Write the wav file
- Command::new("espeak")
- .arg("-w")
- .arg(&file_path)
- .arg(text)
- .status()?;
-
- // Read the wav file bytes
- let bytes = std::fs::read(&file_path)?;
-
- // Delete the file
- std::fs::remove_file(file_path)?;
-
// Convert to base64
- let base64 = base64::encode(bytes);
-
- Ok(base64)
+ base64::encode(concat_letters)
}
#[cfg(test)]
mod tests {
- use crate::captcha_espeak_wav_base64;
use lemmy_api_common::check_validator_time;
use lemmy_db_queries::{establish_unpooled_connection, source::local_user::LocalUser_, Crud};
use lemmy_db_schema::source::{
@@ -253,9 +216,4 @@ mod tests {
let num_deleted = Person::delete(&conn, inserted_person.id).unwrap();
assert_eq!(1, num_deleted);
}
-
- #[test]
- fn test_espeak() {
- assert!(captcha_espeak_wav_base64("WxRt2l").is_ok())
- }
}
diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs
index 656ddf971..831e38a17 100644
--- a/crates/api/src/local_user.rs
+++ b/crates/api/src/local_user.rs
@@ -1,4 +1,4 @@
-use crate::{captcha_espeak_wav_base64, Perform};
+use crate::{captcha_as_wav_base64, Perform};
use actix_web::web::Data;
use anyhow::Context;
use bcrypt::verify;
@@ -135,13 +135,11 @@ impl Perform for GetCaptcha {
let answer = captcha.chars_as_string();
- let png_byte_array = captcha.as_png().expect("failed to generate captcha");
-
- let png = base64::encode(png_byte_array);
+ let png = captcha.as_base64().expect("failed to generate captcha");
let uuid = uuid::Uuid::new_v4().to_string();
- let wav = captcha_espeak_wav_base64(&answer).ok();
+ let wav = captcha_as_wav_base64(&captcha);
let captcha_item = CaptchaItem {
answer,
diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs
index 7767da460..7b732412c 100644
--- a/crates/api_common/src/person.rs
+++ b/crates/api_common/src/person.rs
@@ -39,8 +39,8 @@ pub struct GetCaptchaResponse {
#[derive(Serialize)]
pub struct CaptchaResponse {
- pub png: String, // A Base64 encoded png
- pub wav: Option, // A Base64 encoded wav audio
+ pub png: String, // A Base64 encoded png
+ pub wav: String, // A Base64 encoded wav audio
pub uuid: String,
}
diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile
index 954c85c84..5d2acec7f 100644
--- a/docker/dev/Dockerfile
+++ b/docker/dev/Dockerfile
@@ -49,9 +49,6 @@ FROM alpine:3.12 as lemmy
# Install libpq for postgres
RUN apk add libpq
-# Install Espeak for captchas
-RUN apk add espeak
-
RUN addgroup -g 1000 lemmy
RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy
diff --git a/docker/dev/volume_mount.dockerfile b/docker/dev/volume_mount.dockerfile
index 0cb036247..d848e0ea6 100644
--- a/docker/dev/volume_mount.dockerfile
+++ b/docker/dev/volume_mount.dockerfile
@@ -19,9 +19,9 @@ RUN --mount=type=cache,target=/app/target \
FROM ubuntu:20.10
-# Install libpq for postgres and espeak
+# Install libpq for postgres
RUN apt-get update -y
-RUN apt-get install -y libpq-dev espeak
+RUN apt-get install -y libpq-dev
# Copy resources
COPY config/defaults.hjson /config/defaults.hjson
diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile
index 2ad601aec..88a05fb26 100644
--- a/docker/prod/Dockerfile
+++ b/docker/prod/Dockerfile
@@ -49,9 +49,6 @@ FROM alpine:3.12 as lemmy
# Install libpq for postgres
RUN apk add libpq
-# Install Espeak for captchas
-RUN apk add espeak
-
RUN addgroup -g 1000 lemmy
RUN adduser -D -s /bin/sh -u 1000 -G lemmy lemmy
diff --git a/docker/prod/Dockerfile.arm b/docker/prod/Dockerfile.arm
index 61d1f86c9..b3eacb4f9 100644
--- a/docker/prod/Dockerfile.arm
+++ b/docker/prod/Dockerfile.arm
@@ -22,9 +22,9 @@ RUN cp ./target/release/lemmy_server /app/lemmy_server
# The Debian runner
FROM debian:buster-slim as lemmy
-# Install libpq for postgres and espeak for captchas
+# Install libpq for postgres
RUN apt-get update \
- && apt-get -y install --no-install-recommends espeak postgresql-client libc6 libssl1.1 \
+ && apt-get -y install --no-install-recommends postgresql-client libc6 libssl1.1 \
&& rm -rf /var/lib/apt/lists/*
RUN addgroup --gid 1000 lemmy
From bf7558830f6bd711d259f6641c52e8395bbab437 Mon Sep 17 00:00:00 2001
From: Dessalines
Date: Thu, 1 Apr 2021 13:57:45 -0400
Subject: [PATCH 04/14] Changing preferred to display name. Fixes #1211
---
api_tests/package.json | 2 +-
api_tests/src/user.spec.ts | 4 ++--
api_tests/yarn.lock | 8 ++++----
crates/api/src/local_user.rs | 10 +++++-----
crates/api_common/src/person.rs | 2 +-
crates/apub/src/objects/person.rs | 9 +++++----
crates/db_queries/src/source/person.rs | 16 ++++++++--------
crates/db_schema/src/schema.rs | 6 +++---
crates/db_schema/src/source/person.rs | 14 +++++++-------
crates/db_views/src/comment_view.rs | 2 +-
crates/db_views/src/post_view.rs | 2 +-
crates/utils/src/test.rs | 8 ++++----
crates/utils/src/utils.rs | 6 ++----
.../down.sql | 6 ++++++
.../up.sql | 6 ++++++
15 files changed, 56 insertions(+), 45 deletions(-)
create mode 100644 migrations/2021-04-01-173552_rename_preferred_username_to_display_name/down.sql
create mode 100644 migrations/2021-04-01-173552_rename_preferred_username_to_display_name/up.sql
diff --git a/api_tests/package.json b/api_tests/package.json
index 7cb949594..1b0583c4f 100644
--- a/api_tests/package.json
+++ b/api_tests/package.json
@@ -16,7 +16,7 @@
"eslint": "^7.18.0",
"eslint-plugin-jane": "^9.0.3",
"jest": "^26.6.3",
- "lemmy-js-client": "0.10.0-rc.13",
+ "lemmy-js-client": "0.11.0-rc.1",
"node-fetch": "^2.6.1",
"prettier": "^2.1.2",
"ts-jest": "^26.4.4",
diff --git a/api_tests/src/user.spec.ts b/api_tests/src/user.spec.ts
index a10876cf5..5d10fd043 100644
--- a/api_tests/src/user.spec.ts
+++ b/api_tests/src/user.spec.ts
@@ -19,7 +19,7 @@ let apShortname: string;
function assertUserFederation(userOne: PersonViewSafe, userTwo: PersonViewSafe) {
expect(userOne.person.name).toBe(userTwo.person.name);
- expect(userOne.person.preferred_username).toBe(userTwo.person.preferred_username);
+ expect(userOne.person.display_name).toBe(userTwo.person.display_name);
expect(userOne.person.bio).toBe(userTwo.person.bio);
expect(userOne.person.actor_id).toBe(userTwo.person.actor_id);
expect(userOne.person.avatar).toBe(userTwo.person.avatar);
@@ -49,7 +49,7 @@ test('Set some user settings, check that they are federated', async () => {
lang: '',
avatar,
banner,
- preferred_username: 'user321',
+ display_name: 'user321',
show_avatars: false,
send_notifications_to_email: false,
bio,
diff --git a/api_tests/yarn.lock b/api_tests/yarn.lock
index 8f8abf873..f3b8e603f 100644
--- a/api_tests/yarn.lock
+++ b/api_tests/yarn.lock
@@ -3233,10 +3233,10 @@ language-tags@^1.0.5:
dependencies:
language-subtag-registry "~0.3.2"
-lemmy-js-client@0.10.0-rc.13:
- version "0.10.0-rc.13"
- resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.10.0-rc.13.tgz#ea2e88857243374d7fbd49ee6b4bb94c34359d85"
- integrity sha512-zodvYkwBYR7iP27ah6L/QPUphUUdq38kCH7QF2CUYBrsSAEkGmq2kdz+iusnQ1Ht7Ad80GtYycFprsZBveV5eQ==
+lemmy-js-client@0.11.0-rc.1:
+ version "0.11.0-rc.1"
+ resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.11.0-rc.1.tgz#0031676be9fc787157a21dd3f5095dd1ee9e6a57"
+ integrity sha512-dtpxe/hHTbYEv2WnfGkAieOB9jyKUVED+y4DosUp/FcaatjPcMTiKOvCdMNjlvvG/9GyclWEoyNitPEsvJwjmg==
leven@^3.1.0:
version "3.1.0"
diff --git a/crates/api/src/local_user.rs b/crates/api/src/local_user.rs
index 656ddf971..2fb4056f2 100644
--- a/crates/api/src/local_user.rs
+++ b/crates/api/src/local_user.rs
@@ -60,7 +60,7 @@ use lemmy_utils::{
email::send_email,
location_info,
settings::structs::Settings,
- utils::{generate_random_string, is_valid_preferred_username, naive_from_unix},
+ utils::{generate_random_string, is_valid_display_name, naive_from_unix},
ApiError,
ConnectionId,
LemmyError,
@@ -174,7 +174,7 @@ impl Perform for SaveUserSettings {
let banner = diesel_option_overwrite_to_url(&data.banner)?;
let email = diesel_option_overwrite(&data.email);
let bio = diesel_option_overwrite(&data.bio);
- let preferred_username = diesel_option_overwrite(&data.preferred_username);
+ let display_name = diesel_option_overwrite(&data.display_name);
let matrix_user_id = diesel_option_overwrite(&data.matrix_user_id);
if let Some(Some(bio)) = &bio {
@@ -183,8 +183,8 @@ impl Perform for SaveUserSettings {
}
}
- if let Some(Some(preferred_username)) = &preferred_username {
- if !is_valid_preferred_username(preferred_username.trim()) {
+ if let Some(Some(display_name)) = &display_name {
+ if !is_valid_display_name(display_name.trim()) {
return Err(ApiError::err("invalid_username").into());
}
}
@@ -235,7 +235,7 @@ impl Perform for SaveUserSettings {
avatar,
banner,
inbox_url: None,
- preferred_username,
+ display_name,
published: None,
updated: Some(naive_now()),
banned: None,
diff --git a/crates/api_common/src/person.rs b/crates/api_common/src/person.rs
index 7767da460..d95fed6b5 100644
--- a/crates/api_common/src/person.rs
+++ b/crates/api_common/src/person.rs
@@ -53,7 +53,7 @@ pub struct SaveUserSettings {
pub lang: Option,
pub avatar: Option,
pub banner: Option,
- pub preferred_username: Option,
+ pub display_name: Option,
pub email: Option,
pub bio: Option,
pub matrix_user_id: Option,
diff --git a/crates/apub/src/objects/person.rs b/crates/apub/src/objects/person.rs
index 25c785d84..3e468d5c8 100644
--- a/crates/apub/src/objects/person.rs
+++ b/crates/apub/src/objects/person.rs
@@ -64,7 +64,8 @@ impl ToApub for DbPerson {
set_content_and_source(&mut person, bio)?;
}
- if let Some(i) = self.preferred_username.to_owned() {
+ // In apub, the "name" is a display name
+ if let Some(i) = self.display_name.to_owned() {
person.set_name(i);
}
@@ -161,7 +162,7 @@ impl FromApubToForm for PersonForm {
.preferred_username()
.context(location_info!())?
.to_string();
- let preferred_username: Option = person
+ let display_name: Option = person
.name()
.map(|n| n.one())
.flatten()
@@ -176,12 +177,12 @@ impl FromApubToForm for PersonForm {
.map(|s| s.to_owned().into());
check_slurs(&name)?;
- check_slurs_opt(&preferred_username)?;
+ check_slurs_opt(&display_name)?;
check_slurs_opt(&bio)?;
Ok(PersonForm {
name,
- preferred_username: Some(preferred_username),
+ display_name: Some(display_name),
banned: None,
deleted: None,
avatar: avatar.map(|o| o.map(|i| i.into())),
diff --git a/crates/db_queries/src/source/person.rs b/crates/db_queries/src/source/person.rs
index 35ed540c0..2d332bd01 100644
--- a/crates/db_queries/src/source/person.rs
+++ b/crates/db_queries/src/source/person.rs
@@ -15,7 +15,7 @@ mod safe_type {
type Columns = (
id,
name,
- preferred_username,
+ display_name,
avatar,
banned,
published,
@@ -37,7 +37,7 @@ mod safe_type {
(
id,
name,
- preferred_username,
+ display_name,
avatar,
banned,
published,
@@ -63,7 +63,7 @@ mod safe_type_alias_1 {
type Columns = (
id,
name,
- preferred_username,
+ display_name,
avatar,
banned,
published,
@@ -85,7 +85,7 @@ mod safe_type_alias_1 {
(
id,
name,
- preferred_username,
+ display_name,
avatar,
banned,
published,
@@ -111,7 +111,7 @@ mod safe_type_alias_2 {
type Columns = (
id,
name,
- preferred_username,
+ display_name,
avatar,
banned,
published,
@@ -133,7 +133,7 @@ mod safe_type_alias_2 {
(
id,
name,
- preferred_username,
+ display_name,
avatar,
banned,
published,
@@ -236,7 +236,7 @@ impl Person_ for Person {
diesel::update(person.find(person_id))
.set((
- preferred_username.eq::