Fundamentos de Programación

1

Bienvenida a Platzi: ¿qué necesitas para tomar el curso?

2

Programación en Navegadores: Primeros Pasos

3

Crea tu primer sitio web

4

Sitios web con HTML

5

Estructura de árbol en HTML

6

Instalando tu primer editor de código

7

Cómo declarar variables y usar prompt

8

Algoritmo de piedra, papel o tijera

9

Algoritmo avanzado de piedra, papel o tijera

10

Aleatoriedad

11

Refactor del código usando funciones

12

Ciclos

13

Gana 3 veces

14

Archivos de HTML y JavaScript

15

¿Qué es el DOM?

Quiz: Fundamentos de Programación

Desarrollando un juego con HTML y JavaScript

16

Maquetación con HTML

17

Sección de elegir mascota

18

¿Dónde ubicar la etiqueta script? Conectando HTML con JavaScript

19

Escuchando eventos con JavaScript

20

addEventListener

21

Manipulación del DOM

22

Enemigos aleatorios

23

Ataques en JavaScript

24

Ataques aleatorios del enemigo

25

Imprimiendo ataques del enemigo

26

¿Ganaste, perdiste o empataste?

27

Tablas de verdad

28

Creando el contador de vidas

29

¿Quién ganó el juego?

30

Reiniciando el juego

31

Ocultando elementos HTML con JS para mejorar la UX del juego

Quiz: Desarrollando un juego con HTML y JavaScript

Estilos con CSS

32

Anatomía de CSS

33

Tipos de display

34

Flexbox

35

Modelo de caja

36

Imágenes para los Mokepones

37

Estilos del botón

38

Adaptando HTML al diseño del juego

39

Layout: título y ataques

40

Adaptando JavaScript al diseño del juego

41

CSS Grid

42

Responsive Design

43

Detalles finales

Quiz: Estilos con CSS

Optimización de código

44

Revisión de código

45

Don't repeat yourself (DRY)

46

Clases y objetos

47

Clases y objetos de Mokepon

48

Arrays o arreglos

49

Objetos vs. arreglos

50

Ciclos: manipulando el DOM con iteradores

51

Declaración lenta de variables

52

Una sola fuente de la verdad

53

Mascotas aleatorias con arreglos

54

Ataques dinámicos por cada mascota: extraer

55

Renderizado dinámico en HTML

56

Eventos de click dinámicos

57

Secuencia de ataques del enemigo

58

Iniciando el combate

59

Resolviendo el reto de condicionales

60

Optimizando el frontend del juego

Quiz: Optimización de código

Mapa con canvas

61

Introducción a canvas: dibujando con JavaScript

62

Moviendo a Capipepo hacia la derecha

63

Movimiento hacia todas las direcciones

64

Movimientos con el teclado

65

Imágenes y personajes de fondo

66

Métodos en las clases

67

Obstáculos y colisiones

68

Combate entre mokepones colisionados

69

Mapa responsive

70

Botones bonitos y viewport

Quiz: Mapa con canvas

Backend: videojuego multijugador

71

¿Qué es backend?

72

Instalación de Node.js y NPM

73

Terminal de comandos y Node.js

74

Servidor web con Express.js

75

HTTP, localhost, servidores y puertos

76

Express.js y fetch: API REST con JavaScript

77

JSON y POST: mokepon online

78

Transmisión de coordenadas

79

Mokepones dinámicos en el mapa

80

Optimizando el mapa del juego

81

Batalla entre jugadores

82

Consumiendo la API de ataques del enemigo

Quiz: Backend: videojuego multijugador

Próximos pasos

83

Probando el juego en varios dispositivos

84

¿Y ahora qué curso tomar?

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Express.js y fetch: API REST con JavaScript

76/84
Recursos

Te encuentras desarrollando tu primer backend y tu primera API. Un backend está compuesto por múltiples endpoints que serán utilizados por el front-end. Es momento de conectar ambos mundos.

¿Qué es un endpoint?

Un nuevo término que debes conocer y que siempre te acompañará. Llamamos endpoint, o punto final, a cada URL que el backend exponer para que el front-end utilice, ya sea para la obtención de datos, creación, actualización, etc.

Cada acción que tu backend pueda realizar, la misma se ejecutará a través de un endpoint.

Creando tu primer endpoint

Crear un endpoint con ExpressJS para enviar datos a un cliente es muy sencillo. Ya tienes tu servidor levantado, al mismo vamos a agregarle endpoints para la obtención de datos.

const express = require('express');
const app = express();
const port = 3000;

// Endpoint para obtener datos
app.get('/datos', (req, res) => {
  const datos = '12345';
  res.send(datos);
});

app.listen(port, () => {
  console.log(`¡Servidor listo!`);
});

Observa el endpoint /datos, el mismo devuelve un número. Accede a este endpoint desde la URL localhost:3000/datos y visualizarás los mismos en el navegador.

Pero la obtención de esta información por parte de un cliente no suele realizarse directamente por el navagador. En su lugar, utilizamos un cliente HTTP para lograr conectar en backend y el front-end.

Conexión de backend y front-end

Las consultas por parte de un front-end al backend se realizan por medio de un cliente HTTP. El mismo es una librería que te permitirá hacer consultas a los endpoints y obtener información.

Encontrarás muchos clientes HTTP en NPM. Para este ejemplo, usaremos uno llamado fetch que es propio de Javascript y no tendremos que instalar ninguna dependencia.

En los archivos JS de tu front-end, puedes realizar solicitudes HTTP de la siguiente manera:

fetch('http://localhost:3000/datos')
  .then(response => response.json())
  .then(data => {
    console.log(data);      // 12345
  });

Al ejecutar esta función asíncrona, obtendrás los datos del backend en la variable data pudiendo manipular los mismos y mostrarlos en el HTML de tu página.

Problemas de CORS

Puedes tener con un problema trivial al querer realizar consultas a un backend. Mejor dicho… vas a tener este problema.

CORS es un pequeño problema con el que te toparás mil veces en tu vida como programador. Pero no te preocupes, es de fácil resolución.

La consola de desarrollo de los navegadores te permitirá obtener más información cuando las cosas no funcionen. Si te encuentras con un error similar a:

Ejemplo problema de CORS

Indica un problema de CORS que significa, por sus siglas en español, Intercambio de Recursos de Origen Cruzado. Es una medida de seguridad de los backend para que no cualquier cliente, o cualquier front-end, realice consultas al mismo.

El backend debe permitir explícitamente que un cliente haga consultas, de lo contrario rechazará las mismas.

Habilita CORS instalando su respectiva dependencia con npm install cors y realizando la importación de la misma.

// Importamos CORS
const cors = require('cors');

// Activamos CORS
app.use(cors());

De esta forma, el backend está listo para recibir consultas y el front-end podrá obtener los datos y trabajar con los mismos.

Conclusión

Acabas de dar tu primer paso en el desarrollo full-stack, o sea, en el desarrollo backend y front-end. ¡Felicidades!

Es solo el primer paso para integrar estos los dos mundos y poder visualizar en un front-end, los datos que el backend procesa o almacena en una base de datos.


Contribución creada por: Kevin Fiorentino (Platzi Contributor).

Aportes 70

Preguntas 56

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Por si les causan dudas los .then

  1. fetch(url) hace un GET (una petición para obtener algo) a la URL que se le especifique
  2. Esta función nos retornará algo (lo que sea que se haya definido en el código del servidor).
  3. No podemos trabajar con lo que nos retorne directamente, ya que el servidor se tomará un tiempo en responder.
  4. Para eso utilizaremos el .then(func), que ejecutará el código de la función que le demos (en este caso, func), pasándole la respuesta del servidor como parámetro.
  5. El .then suele ir por debajo de la función que hayamos llamado (fetch en este caso) e indentado, por pura estética nada más. Nótese que se puede hacer fetch(url).then(func) sin dejar ningún espacio.

Así, un ejemplo de código podría ser:

function decirHola(res) {
	if (res.ok) {
		console.log("¡Todo bien!");
	}
}

fetch("https://google.com")
	.then(decirHola)

Este código enviaría un request a https://google.com y, una vez tuviera una respuesta del servidor, haría decirHola(respuesta), siendo respuesta la respuesta que haya dado el servidor de esa URL.

Lo que pasa es que muchas veces la función que usamos (en este caso decirHola) no se define aparte, sino que se crea al instante. Este concepto es conocido como función anónima y se ve así:

fetch("https://google.com")
	.then(function(res) { // abrimos la función anónima
		// aquí el código de la función
		if (res.ok) {
			console.log("¡Todo bien!");
		}
	}) // el corchete cierra la función, el paréntesis cierra al .then

Este concepto es oro en polvo, son las promesas de JavaScript, así que les invito a investigar sobre ello.

No olviden que el objeto “Class Jugador” se escribe con la J mayúscula, por ese error no pude avanzar y perdí tiempo, un saludo, espero les sirva.

Estoy viendo que ya vamos por la clase 76, a este punto muchas personas de las que comenzaron, no llegan, se dan cuenta que tal vez no es lo de ellos o x razones. pero aprovecho para felicitarnos por haber llegado a este punto y yo solo digo… "no te acabes cursoooo!!! " jajajaja

Wooooooooooooooowww!!! Me toy enamorando :3

cuando estén en la parte de poner ${Math.random} asegúrense que son las comillas EXACTAS que son estas: ``
se las dejo para que las copien o si no con el comando Ctrl + alt + (la tecla que tenga la comilla), ya que yo estuve como media hora para encontrar el error y eran esas comillas xd

La verdad uno queda loco…
El asunto radica en que no se nos explica realmente la finalidad de lo que hacemos, muestran todo el procedimiento pero hasta ahi.

si empezaran por mostrar que es lo que se busca con los que haremos quiza uno tendria mejor asociación con los conceptos

Me paso que habia cerrado todo al terminar la clase pasada, al abrirlo de nuevo quice seguir con el contro + c del sgundo 50 y continuar a la par, no lo logre por que debia ubicarme de nuevo en la carpeta donde tengo mis archivos, tal cual como el inicio del video pasado, dejo el aportesito por si a alguien mas le pasa, casi no doy con el chiste

Si no os sale el console.log() en la pagina del html aseguraos que cuando llamáis la función unirseAlJuego() tengáis puestos los paréntesis ()

Que tengan un buen día 🎈

Yo dandome cuenta que aun está ahí el typo del profe Diego, bueno creo que el fue, que colocó Mokepono, en lugar de Mokepon.

Les quiero contar que había dejado el curso parado y lo he retomado 2 meses después. Es todo un reto retomar pero aquí estoy, necesito terminarlo para poder continuar. Este curso se llama básico pero se que tiene cosas muy avanzadas que seguramente vamos a ver más adelante con mayor detenimiento.

Para posibles futuros errores:
Acordaros de tener el servidor funcionando. Si no lo está, os dará error y no os dará el número de jugador. (30’ intentando ver porque no me salía)

No sabía que el res.text y res.json también eran promesas, lol

me quedo con frontend !!!

Por si no saben sacar (``) o no lo encuentran… Pueden usar Alt + 96 y ahí les saldrá las comillas 😃

Me pregunto . que tiene de basico la enseñanza de back end que nos estan dando ? … jaja yo esperaba explicaciones y enseñanzas basicas , pensando en alguien que de verdad esta partiendo en esto , no creo que esta parte de la enseñanza este pensado en gente que recien comienza . 😦 la verdad desmotiva un poco que se salten tantos conceptos y que den por hecho que los dominaramos , si veo mucha gente comentando con conocimientos previos pero para alguien que recien parte en la programacion esto es mas desmotivante que motivante en si , por que va todo rapido y con apenas explicacion como si ya los de conocimiento basico lo supieramos , esperaba que aqui es cuando nos explican conceptos basicos o usos de los comandos en forma basica , no por que no quiera avanzar sino que por que primero pensaba que seteariamos las bases , pero veo que todo ya se da por hecho . Frustracion y estar perdido es poco! bueno como sea como dijo alguien por ahi!! vamos que queda poco!! por algo llegamos hasta aqui , solo que aburre un poco y cansa hacer todo copy paste sin entender mucho ni recibir explicaciones contextuales 🤷

Con async y await queda mas legible el código

const unriseAlJuego = async () => {
  let response = await fetch(http://localhost)
  let userData = await response.json();

  console.log(userData)
}

sin embargo es bueno saber como funciona una petición con .then ✌️

éramos cientos todos animados :C, quedamos pocos

por algun motivo lo escribí exactamente igual y no funciona jajaja

La prf me parece muy buena y se nota que está muy clara en lo que habla, pero, su clase la da (a mi parecer), tipo repaso, ignorando que muchos aca no estamos tan empapados en el tema que imparte… Estaria genial que se tome un poco mas de tiempo y explicar el paso a paso de lo que hace…

Me salia error y tenia el servidor apagado jajajajjajaj

Si no les carga la página de localhost deben poner esto en la consola: node index.js

Créditos a @ric.arellano92!!!
Para evitar el error “mokepon.js:448 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘nombre’)” lo que hice fue agregar un if que evalué si el mokepon existe o no, esta validación también se aplica en la parte de pintar mokeponEnemigo:

//____---------------------Al recuperar enemigos--------------------------
                mokeponesEnemigos = enemigos.map(function (enemigo)
                {
                    let mokeponEnmigo = null
                    if(enemigo.mokepon != undefined)
                    {
                        const mokeponNombre = enemigo.mokepon.nombre 
                        switch (mokeponNombre)
                        {
                        case "Hipodoge":
                            mokeponEnmigo = newMokepon('Hipodoge', './assets/mokepons_mokepon_hipodoge_attack.png', 5, './assets/hipodoge.png', enemigo.id)
                                break
                            case "Capipepo":
                                mokeponEnmigo = newMokepon('Capipepo', './assets/mokepons_mokepon_capipepo_attack.png', 5, './assets/capipepo.png', enemigo.id)
                                break
                            case "Ratigueya":
                                mokeponEnmigo = newMokepon('Ratigueya', './assets/mokepons_mokepon_ratigueya_attack.png', 5, './assets/ratigueya.png', enemigo.id)
                                break
                            default:
                                break
                        }

                        mokeponEnmigo.x = enemigo.x
                        mokeponEnmigo.y = enemigo.y
                    }
                        return mokeponEnmigo
                })

//---------------------------------Al tratar de pintar enemigos----------------------------------------
        mokeponesEnemigos.forEach(function (mokepon)
        {
            if(mokepon != undefined){
                mokepon.pintarMokepon()
                revisarColision(mokepon)
            }
        })

Re subí la respuesta de @ric.arellano92 porque estuve rompiéndome la cabeza durante una semana y quiero que otros lo puedan solucionar, ya que desde las carpetas del curso da error.

Cada vez que me marea una clase una voz de freddy me dice "NO APAGUES EL CEREBRO" XD.
![](https://static.platzi.com/media/user_upload/image-7a69fe80-5d26-4af7-b31b-5c31b95326b1.jpg)

Sé que probablemente necesitaría el curso que tienen de backend en los recursos para entenderlo 100%, pero sí consigo seguir la clase y ya apenas quedan 6 vídeos para terminar este proyecto. 🫡 Estoy muy orgullosa de mí y de todos los que estamos llegando hasta aquí con nuestros mokepones.

Buen día, me salió el siguiente error en el localhost: "ReferenceError: math is not defined    at C:\Users\Gato\Desktop\mokepon\index.js:15:16    at Layer.handle \[as handle\_request] (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\layer.js:95:5)    at next (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\route.js:144:13)    at Route.dispatch (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\route.js:114:3)    at Layer.handle \[as handle\_request] (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\layer.js:95:5)    at C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\index.js:284:15    at Function.process\_params (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\index.js:346:12)    at next (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\index.js:280:10)    at expressInit (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\middleware\init.js:40:5)    at Layer.handle \[as handle\_request] (C:\Users\Gato\Desktop\mokepon\node\_modules\express\lib\router\layer.js:95:5)" llevo como una semana intentando y nada que logro corregirlo, alguien sabría como hacerlo?

Se puso bastante complejo el curso ajajajaj

Gracias a los dioses del internet que dejamos CSS atrás y nos pusimos serios😍

Buenas noches, tengo un problema cuando trato de hacer el localhost:8080/inirse en el navegador me sale unas lineas y me dice que hay una referencia de erro ya compare mi codigo y creo tenerlo bien. si alguien lo puede revisar y me decir cual es el erro.

<code> const express = require("express")

const app = express()

const Jugadores = []

class Jugador {
    constructor (id) {
        this.id = id
    }
}

app.get("/unirse", (req, res) => {
    const id = `${Math.random()}`

    const Jugador = new Jugador(id)
    Jugadores.push(Jugador)

    res.send(id)
})

app.listen(8080, () => {
    console.log("servidor funcionando")
})

Dos cosas:

  1. En recursos de la clase esta la solución del CORS.
  2. Como ya trabajamos en el servidor hay que tener todos los archivos dentro de la carpeta que se instaló el servidor.

cuando inicio el local host me sale Cannot GET /unirse

Funcionando✅

Hola ¿Con qué comando de teclas puedo hacer que aparezca la línea en de la TERMINAL donde ubica mi archivo? Después de que pongo a funcionar el servidor, tengo que eliminar esa TERMINAL para que esa línea de código vuelva a aparecer.
¿Por qué no me aparece nada en la consola? Ni siquiera me sale el id TT
¡Quiero llorar de la felicidad!
:)
Hola , me encontre con el problema Cannot GET/, para resolverlo tuve que añadir un app.get antes solo con ¨/", y luego ya usar el unirse
Las indicaciones de la sección recursos no aclarar el video, incluso es información muy distinta.
La verdad no entendí mucho seguí todos los pasos pero al final me sale este error: Error: Cannot find module 'D:\EDGAR\Curso Basico de Programacion\mokepon\index,js' at Module.\_resolveFilename (node:internal/modules/cjs/loader:1144:15) at Module.\_load (node:internal/modules/cjs/loader:985:27) at Function.executeUserEntryPoint \[as runMain] (node:internal/modules/run\_main:135:12) at node:internal/main/run\_main\_module:28:49 { code: 'MODULE\_NOT\_FOUND', requireStack: \[] }

si no les sale el local host cambien las comillas dobles ("") por comillas simples(’ ‘)
ejemplo =>
app.get(’/unirse’, (req, res) => {
const id = ${Math.random()}
const jugador = new Jugador(id)
jugadores.push(jugador)

recuerden siempre checar que estén en la carpeta correcta.

Esto es increíble.

extrañamente como es la tecnologia muchas veces ,no me cargaba el numero aleatorio que sesupone que tiene que arrojar cuando vamos al server en “htt://localhost:8080/unirse” …etonces lo que hice es apagar la terminal con “Ctrl +C” y luego la encendi con “node index.js” luego fui a cargar nuevamente en “htt://localhost:8080/unirse” y ahi si me arrojo el numero aleatorio , la tecnologia y el resetear jaja nunca falla …un clasico!

vengo a dar mi aporte.

Yo tenia el error Access-Control-Allow-Origin pero ya tenia la clase en curso, la repase varias veces, descrague el codigo lo compare con vs todo estaba bien y me salia el mismo error, y en el mokepon de la clase que descargue tambien tenia el mismo error.

A prueba y error y gracias a el comentario en la comunidad dev de discord de platzi, instale la extension live-server en vs y bualaaaaa

Funciona.
Ahora me pregunto que pasoo y como sirve esto.
si algun profe lee este comentario o estudiante que sepa, le agradezco la aclaracion.

Antes de poder recibir una respuesta de nuestro servidor, primero se debe verificar si esta permitido llamar al servicio desde este origen (nuestro frontend) y para eso revisaremos que nos pasa como parametro la variable res en la consola, de esta denegarse por un error seria momento de crear una cabecera desde nuestro backend para permitirnos utilizar servicios desde este origen

localhost --> servidor local

get --> permite solicitar recursos

post --> permite enviar datos

.then --> recibe una funcion

res.setheader() --> permite que se realicen solicitudes desde el lugar especificado

fetch --> permite acceder y manipular solicitudes

Me cuesta seguirle el ritmo a la profesora. Debe ser porque backend no es lo mío 😦

recuerden poner el Math.random de manera correcta — Math.random()

Me encanta la manera de explicar de la profe Diana Martinez. Bastante clara la informacion que es bastante compleja! Felicidades 😄

La función fetch() en JavaScript puede recibir uno o dos parámetros:
.
1 - La URL de la solicitud: Este es el único parámetro obligatorio que se debe proporcionar a la función fetch(). Representa la dirección web de la cual se espera obtener una respuesta.
.
2 - Las opciones de configuración: Este es un parámetro opcional que se utiliza para proporcionar configuraciones adicionales para la solicitud. Este parámetro es un objeto que puede tener los siguientes atributos:
.

  • method: El método HTTP de la solicitud, como GET, POST, PUT, DELETE, etc.
    .
  • headers: Los encabezados HTTP de la solicitud, como “Content-Type” y “Authorization”. Este es un objeto con pares clave-valor.
    .
  • body: El cuerpo de la solicitud, como una cadena de texto, un objeto FormData, un objeto Blob, un objeto BufferSource, o un objeto URLSearchParams, entre otros.
    .
  • mode: El modo de la solicitud, como “cors”, “same-origin”, o “no-cors”.
    .
  • cache: El modo de caché de la solicitud, como “default”, “no-store”, “reload”, o “no-cache”.
    .
  • redirect: El modo de redireccionamiento de la solicitud, como “follow”, “error”, o “manual”.
    .
  • referrer: El valor del encabezado Referer de la solicitud.
    .
  • referrerPolicy: La política de referer de la solicitud, como “no-referrer”, “no-referrer-when-downgrade”, o “origin”.
    .
  • integrity: El valor de integridad de la solicitud, como un hash criptográfico.

.
En resumen, fetch() puede recibir la URL de la solicitud como único parámetro obligatorio, pero también puede recibir un objeto con opciones de configuración adicionales para personalizar la solicitud y la respuesta.

Si quieren entender mas acerca de este tema de las** Promesas en JS** recomiendo mucho este video https://www.youtube.com/watch?v=ppzrpTjwEC8&ab_channel=jonmircha . En este canal tambien podran encontrar muchos otros videos de varios temas de Javascript para reforzar.

Que increible, me estoy enamorando mas y mas de la ptogramacion

Me parecio increible el como se utiliza un API Rest en un FrontEnd como JS, me quede impresionado. Y la forma que se declara para obtener el resultado de su funcionamiento. Espero seguir aprendiendo mas.

creditos a :Chema Ferrández

Para posibles futuros errores:
Acordaros de tener el servidor funcionando. Si no lo está, os dará error y no os dará el número de jugador. (30’ intentando ver porque no me salía)

Para sacar el “console.log” de manera rápida, solo escriban “log” se van a la segunda opcion del vscode y le dan a enter o tabulan

Al principio no me tomada el ID aleatorio y salia error, lo corregi pero aun asi salia el mismo error, luego reinicie el servidor y ahi si funciono correctamente por si les pasa a ustedes

asíncrona : quiere decir que no sabemos cuanto tardar en darnos la respuesta el servidor por eso es asíncrona.

puenden instalarse :

npm i nodemon

para no tener que sacar y volver a inciar el servidor en cada cambio.

para usarlo solo tienen que escribir nodemo index.js dentro de la carpeta donde esta index.js

Para detener el Servidor Crtl + C…

media hora viendo que significa ‘function random() { [native code] }’ para darme centa que no le coloque los parentesis a Math.random 😂

estoy muy trabada , se rompio mi juego , no se porque , aparecieron varios archivos mokepon html en mu cpu , desde q estoy utilizando la terminal y ahora es como que toma un codigo que esta incompleto y no funciona el juego

Siento ya que llevo el apellido “Back End”, tal como la Von Der Layen o mejor dicho la Von Der Guerris

Hola me aparece este error, pero no logro identificar la solución.!

Si a alguno le ocurre como a mí que no puede apagar el servidor usen este comendo en la consola:

killall node

todo perfecto pero me cuesta seguirle el codigo a la profe! xq tiene abierta la terminal y casi no se ve! de resto todo OK

Esto esta muy divertido 😅