¿Cómo alojar una aplicación React?

Back4app React Cover

En este artículo, hablaremos sobre React, una de las bibliotecas frontend más populares para crear interfaces de usuario. Primero exploraremos sus ventajas y desventajas, luego veremos cómo crear una aplicación web React y, finalmente, cómo alojarla en Back4app Containers.

¿Qué es React?

React es una biblioteca de JavaScript gratuita y de código abierto para crear interfaces de usuario interactivas. Fue creado por Meta (anteriormente conocido como Facebook) en 2013. En el momento de escribir este artículo, es una de las bibliotecas de interfaz de usuario más populares. Es una herramienta versátil para crear aplicaciones de una sola página (SPA, del inglés “single-page applications”), aplicaciones renderizadas por servidor y aplicaciones nativas (tanto de escritorio como móviles).

React utiliza una arquitectura basada en componentes en la que una página se puede dividir en varias piezas reutilizables o los llamados “componentes”. Esta arquitectura mejora la calidad, la legibilidad y el mantenimiento del código y permite que personas o equipos independientes trabajen juntos.

Otras características importantes de React incluyen:

  • Naturaleza declarativa: los desarrolladores describen el estado deseado de una interfaz de usuario, mientras que React maneja la actualización y la representación eficientes de la interfaz de usuario en función de ese estado.
  • Flujo de datos unidireccional: los datos solo se pueden pasar de padre a hijo.
  • DOM virtual: React usa un DOM virtual para actualizar el DOM que se muestra en el navegador de manera eficiente.
  • Ganchos: funciones simples de JavaScript que se pueden usar para aislar partes de componentes.
  • JSX: sintaxis extendida para JavaScript que es similar a HTML. Permite la ejecución directa de JS, lo que es útil para formatear datos, declaraciones condicionales, bucles y más.

En los últimos meses, React también se convirtió en una herramienta popular para crear aplicaciones full-stack. Eso es gracias a Next.js y Remix, que son dos de los marcos más populares para crear aplicaciones React. Simplifican en gran medida el proceso de desarrollo al proporcionar enrutamiento listo para usar, optimización de imágenes, optimización de fuentes, simplificación de la obtención de datos y más.

Las alternativas de React más populares en 2023 son VueSvelteSolid y Angular.

Para obtener más información sobre las alternativas de React, consulta las 10 mejores alternativas de React.

Beneficios de React

Rendimiento

React usa un DOM virtual para optimizar el proceso de actualización y renderizado. En lugar de manipular directamente el DOM, React crea una representación en memoria de la interfaz de usuario. Luego, actualiza de manera eficiente solo las partes necesarias del DOM, lo que da como resultado una representación más rápida y un rendimiento mejorado.

Arquitectura basada en componentes

React utiliza una arquitectura basada en componentes. Esto permite una gran reutilización del código y una mejor capacidad de mantenimiento del código. Además, facilita la integración de componentes de terceros en su proyecto (por ejemplo, reproductor de video, galería, carrusel).

Para acelerar el proceso de desarrollo, también puede elegir entre varias bibliotecas de componentes React listas para usar, como ChakraUIMUIAntDesign, o React Bootstrap. Alternativamente, puede utilizar TailwindCSS.

Fácil de aprender

Si está familiarizado con JavaScript y la creación de interfaces de usuario, entonces React será bastante fácil de aprender. El equipo de React publicó recientemente nueva documentación, que es mucho mejor que la anterior. Al leer la documentación, comprenderá los conceptos básicos de React, que luego podrá aplicar al crear proyectos del mundo real.

Si es un aprendiz visual, también hay muchos cursos de video de React gratuitos y de pago disponibles en YouTube y Udemy.

Multiplataforma

Al aprender React, podrá codificar aplicaciones web, aplicaciones de escritorio y aplicaciones móviles nativas.

Hay muchas bibliotecas disponibles para crear aplicaciones para una plataforma específica. Si está creando una aplicación móvil, le recomiendo que elija Expo o React Native. Para las aplicaciones de Windows hay react-native-windows y para macOS hay react-native-macos.

Comunidad

React tiene un gran ecosistema y está respaldado por una gran comunidad de desarrolladores. Hay un montón de paquetes en NPM que puede usar en lugar de reinventar la rueda. Se puede encontrar una lista de increíbles paquetes de React en GitHub.

Limitaciones de React

Alto ritmo de desarrollo

A pesar de tener más de diez años, React continúa experimentando un extenso desarrollo. El equipo de React a menudo lanza características que cambian fundamentalmente la forma en que se crean las aplicaciones de React. En 2019 lanzaron ganchos y luego todas las aplicaciones de React cambiaron de componentes basados en clases a componentes basados en funciones. Ahora sucede algo similar con la representación del lado del servidor.

Pero no se preocupe, el equipo de React hace todo lo posible para mantener todo compatible con versiones anteriores.

Depender de bibliotecas de terceros

React es una biblioteca y no un marco. Eso significa que deberá instalar varios paquetes de terceros al crear aplicaciones React complejas. Por ejemplo, React no tiene un sistema de enrutamiento incorporado, optimización de imágenes y manejo de formularios.

Falta de convenciones

React y JavaScript en general carecen de estandarización y convenciones. Hay múltiples formas de lograr algo que a menudo resulta en que los códigos fuente de React sean bastante diferentes de una compañía a otra.

Para escribir un código React limpio, le sugiero que elija una guía de estilo como la Guía de estilo de JavaScript de Airbnb y se ciña a ella.

SEO

React se utiliza principalmente para crear aplicaciones de una sola página (SPA). Los SPA son sitios muy dinámicos que necesitan ejecutar una cantidad decente de JavaScript para renderizar. Además de eso, los SPA no definen una estructura de sitio clara. Estas dos características los hacen menos óptimos para SEO, ya que los rastreadores web y los robots no pueden descifrar la estructura del sitio ni ejecutar JavaScript para obtener el contenido del sitio.

Lógica en Vistas

React no define una separación clara de lógica y vistas. En su lugar, se considera una buena práctica incluir algo de lógica en las vistas (por ejemplo, representación condicional, map()). Los desarrolladores, especialmente los principiantes, a veces malinterpretan esto e incluyen demasiada lógica en las vistas. Eso puede hacer que el código sea menos legible y mantenible.

¿Dónde alojar una aplicación React?

Back4app Containers

Back4app Containers es un increíble contenedor como servicio (CaaS) que le permite implementar aplicaciones dockerizadas con facilidad. La plataforma cierra la brecha entre el desarrollo y la producción al automatizar el proceso de implementación. Como se basa en Docker, puede usarlo para implementar cualquier aplicación. Lo mejor de todo es que ofrece un nivel gratuito que se puede utilizar para alojar aplicaciones sencillas y creación de prototipos.

Otras ventajas de los contenedores de Back4app incluyen:

  • Despliegues automáticos
  • Actualizaciones sin tiempo de inactividad
  • Seguimiento de la implementación en tiempo real
  • Supervisión de aplicaciones en tiempo real
  • Certificado HTTPS/SSL automático

¿Quiere aprender más sobre la tecnología de contenerización? Consulte ¿Qué son los contenedores?

Vercel

Vercel es una poderosa plataforma frontend para implementar aplicaciones estáticas e híbridas. Es una opción popular para las aplicaciones React/Next.js, ya que es fácil de usar, no requiere mucha configuración y tiene un nivel gratuito. Además de eso, es compatible con tecnología de punta, como funciones de vanguardiaintegraciones de aplicaciones y análisis avanzado.

La plataforma tiene una increíble integración de CI/CD y garantiza un tiempo de actividad del 99,99%. Además, Vercel anunció recientemente cuatro tipos diferentes de bases de datos, incluidas Postgres, KV, Blob y Edge Config.

Netlify

Netlify es una plataforma informática de plataforma como servicio (PaaS) para crear, implementar y escalar aplicaciones web. Ofrece características similares a las de Vercel y es su mayor competidor. Es extremadamente fácil de usar y tiene un nivel gratuito. La plataforma admite de forma nativa muchos lenguajes de programación, incluidos Ruby, Node, Python, PHP, Go y Java.

La plataforma se utiliza principalmente para implementar sitios web de empresas, sitios de comercio electrónico, aplicaciones web y otros sitios grandes. La compañía de computación en la nube está bien probada y existe desde 2014.

DigitalOcean App Platform

La plataforma de aplicaciones DigitalOcean es una solución de infraestructura simple y totalmente administrada para crear, implementar y escalar aplicaciones. Se puede usar para implementar aplicaciones web, sitios web, API, sitios estáticos, servicios web y más. La plataforma admite de forma nativa muchos marcos y lenguajes de programación como Python, Django, Go, PHP y Node.js. Además de eso, tiene funciones de seguridad integradas, admite reversiones, alertas, registros avanzados y más.

Puede combinar fácilmente la plataforma de aplicaciones con otros productos DO, como bases de datos administradas, almacenamiento de objetos y funciones en la nube.

¿Cómo alojar una aplicación React?

En la sección de este artículo, veremos cómo crear e implementar una aplicación React en Back4app Containers.

Requisitos previos

  • Experiencia con JavaScript ES6
  • Experiencia con React y React Hooks
  • Comprensión básica de Docker (y la tecnología de contenedores)
  • Node.js y un IDE de JavaScript instalado en su máquina local

Descripción del proyecto

Para demostrar el poder de React y Back4app Containers, crearemos una aplicación web simple de temporizador pomodoro. El cronómetro tendrá dos fases, la “fase de enfoque” y la “fase de descanso”. Una vez finalizada una fase, cambiará automáticamente a la otra fase. Primero codificaremos la aplicación, luego la dockerizaremos y, por último, la implementaremos en Back4app Containers.

react-pomodoro preview

Si está interesado solo en el proceso de implementación, puede omitir la sección “Crear aplicación”.

Crear aplicación

En esta sección, crearemos un nuevo proyecto React, instalaremos ChakraUI e implementaremos la lógica de la aplicación.

Crear aplicación de React

Comience por crear una nueva aplicación React utilizando la herramienta Crear aplicación React (CRA):

$ npx create-react-app react-pomodoro

Esta herramienta generará la estructura del directorio del proyecto, instalará React junto con sus dependencias y las congelará en package-lock.json.

A continuación, navegue hasta la aplicación recién creada:

$ npx react-pomodoro

Inicie el servidor de desarrollo:

$ npm start

Por último, abra http://localhost:3000/ en su navegador favorito y asegúrese de que puede ver la página de destino predeterminada de React.

React Default Project

Instalar ChakraUI

Para simplificar el proceso de creación de UI/UX, utilizaremos ChakraUI, una biblioteca de componentes versátil y fácil de usar.

Abra su interfaz de línea de comandos e instale Chakra junto con sus dependencias:

$ npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion

A continuación, navegue hasta index.js y asegúrese de envolver toda su aplicación en <ChakraProvider>:

// src/index.js

// ...
import {ChakraProvider} from "@chakra-ui/react";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <ChakraProvider>
      <App/>
    </ChakraProvider>
  </React.StrictMode>
);

Genial, ha instalado correctamente ChakraUI. Ahora puede usar los componentes de Chakra, los sistemas de estilo, los ganchos y todo lo demás que Chakra tiene para ofrecer.

Constantes

Como se menciona en la descripción general del proyecto, nuestra aplicación tendrá dos fases:

  1. Fase de enfoque (25 minutos)
  2. Fase de descanso (5 minutos)

Antes de que podamos implementar la lógica de la aplicación, primero definamos algunas constantes en la parte superior de App.js:

// src/App.js

// ...

const FOCUS_KEY = "focus";
const REST_KEY = "rest";

const FOCUS_TIME = 25 * 60;  // 25 minutes, specified in seconds
const REST_TIME = 5 * 60;    // 5 minutes, specified in seconds

const phaseStyles = {
  [FOCUS_KEY]: {
    color: "#ffffff",
    background: "#DF675B",
    backgroundSecondary: "#e1796e",
  },
  [REST_KEY]: {
    color: "#ffffff",
    background: "#71bd4b",
    backgroundSecondary: "#81c260",
  },
};

function App() {
  // ...
}

export default App;

Resumen constante:

  1. FOCUS_KEY y REST_KEY son claves utilizadas para identificar las fases.
  2. FOCUS_TIME y REST_TIME definen la duración de las fases (en segundos).
  3. PhaseStyles define el estilo CSS tanto para el enfoque como para la fase de descanso. En nuestro caso la fase de foco es roja y la fase de descanso es verde.

No se preocupe demasiado por estas constantes, todo tendrá sentido después de las próximas secciones.

Interfaz de usuario

A continuación, modifique el componente App  para representar la interfaz de usuario:

// src/App.js

import {Box, Button, Container, Heading, Link} from "@chakra-ui/react";
import {useEffect, useRef, useState} from "react";

// ...

function App() {

  const [phase, setPhase] = useState(FOCUS_KEY);
  const [timeLeft, setTimeLeft] = useState(FOCUS_TIME);
  const [isRunning, setIsRunning] = useState(false);
  const intervalRef = useRef(null);

  const onFocusClick = () => {};

  const onRestClick = () => {};

  const onStartClick = () => {};

  return (
    <Box
      width="100%" height="100vh"
      background={phaseStyles[phase].background}
      color={phaseStyles[phase].color}
    >
      <Container width="container.xl" py={12} centerContent>
        <Box my={2}>
          <Heading as="h1">react-pomodoro</Heading>
          <Heading as="h2" size="md">a simple react pomodoro app</Heading>
        </Box>
        <Box
          width="100%" display="flex" flexDirection="row"
          color={phaseStyles[phase].background}
          my={2}
        >
          <Button width="100%" mr={2} onClick={onFocusClick}>Focus</Button>
          <Button width="100%" ml={2} onClick={onRestClick}>Rest</Button>
        </Box>
        <Box
          width="100%" display="flex" justifyContent="center"
          background={phaseStyles[phase].backgroundSecondary}
          p={8} my={2} rounded="md"
        >
          <Heading size="4xl">{timeLeft}</Heading>
        </Box>
        <Box width="100%" my={2}>
          <Button 
            width="100%" color={phaseStyles[phase].background}
            onClick={onStartClick}
          >
            {isRunning ? "Pause" : "Start"}
          </Button>
        </Box>
      </Container>
    </Box>
  );
}

export default App;
  1. Usamos los componentes de Chakra (como Box, Button, y Label) para construir la interfaz de usuario.
  2. Usamos el enlace useState() de React para definir el estado de phase, timeLeft e isRunning.
  3. Definimos funciones ficticias como onFocusClick(), onRestClick() y onStartClick() que se activan mediante botones.

Si reinicia el servidor ahora y visita http://localhost:3000, debería ver algo como esto:

react-pomodoro in progress

Se ve decente, pero se vería mejor si timeLeft tuviera un formato más fácil de usar. En lugar de mostrar solo los segundos, podemos analizar timeLeft y mostrar los minutos y segundos restantes como 00:00.

Para lograr eso, defina la siguiente función en la parte superior de App.js:

// src/App.js

const formatTime = (timeInSeconds) => {
  const remainingMinutes = Math.floor(timeInSeconds / 60);
  const remainingSeconds = timeInSeconds % 60;
  return `
      ${String(remainingMinutes).padStart(2, "0")}:
      ${String(remainingSeconds).padStart(2, "0")}
      `;
};

// ...

Luego utilícelo en su JSX así timeFormat(timeLeft).

Lógica

Para definir la lógica de la aplicación, cambie las funciones de clic de la siguiente manera:

// src/App.js

function App() {

  // ...

  const onFocusClick = () => {
    setPhase(FOCUS_KEY);
    setTimeLeft(FOCUS_TIME);
    setIsRunning(false);
  };

  const onRestClick = () => {
    setPhase(REST_KEY);
    setTimeLeft(REST_TIME);
    setIsRunning(false);
  };

  const onStartClick = () => {
    setIsRunning(!isRunning);
  }

  // ...
}
  1. useFocusClick() cambia la fase para enfocar, restablece el tiempo y detiene el temporizador
  2. onRestClick() funciona de manera análoga a useFocusClick(), pero para la fase de descanso
  3. onStartClick() cambia el estado isRunning.

Luego, agregue useEffect() con un intervalo que cuenta regresivamente cada segundo:

// src/App.js

function App() {

  // ...

  useEffect(() => {
    if (isRunning) {
      intervalRef.current = setInterval(() => {
        setTimeLeft(prevState => {
          if (prevState <= 0) {
            setPhase(phase === FOCUS_KEY ? REST_KEY : FOCUS_KEY);
            setIsRunning(false);
            return phase === FOCUS_KEY ? REST_TIME : FOCUS_TIME;
          } else {
            return prevState - 1;
          }
        });
      }, 1000);
    }
    return () => clearInterval(intervalRef.current);
  }, [isRunning, phase]);

  // ...
}

¡Eso es todo! Ejecute su servidor de desarrollo y pruebe la aplicación. Si todo funciona bien, el temporizador debe contar hacia atrás después de presionar “inicio”, hacer una pausa cuando presiona “pausa” y las fases deben cambiar automáticamente después de que el temporizador llegue a cero.

Dockerizando la aplicación

Para implementar una aplicación React en Back4app Containers, primero debe dockerizarla. Para dockerizar una aplicación, generalmente tendrá que hacer lo siguiente:

  1. Defina un Dockerfile.
  2. Cree un archivo .dockerignore.
  3. Cree la imagen y pruébela localmente.

Realicemos estos pasos.

Dockerfile

Un Dockerfile es un documento de texto sin formato que contiene todas las instrucciones que debe realizar el motor de Docker para crear una imagen. Estas instrucciones se pueden usar para configurar el directorio de trabajo, la imagen base, copiar archivos, ejecutar comandos, etc. Las instrucciones suelen estar escritas en mayúsculas y van seguidas directamente de los argumentos. Ejemplo:

INSTRUCTION arguments

Para obtener más información sobre las instrucciones de Dockerfile, consulte la referencia de Dockerfile.

Un React Dockerfile básico se vería así:

FROM node:18-alpine
WORKDIR /app

COPY package.json ./
COPY package-lock.json ./
RUN npm ci

COPY . .

RUN npm run build
RUN npm install -g serve

EXPOSE 5000

CMD ["serve", "-s", "build", "-l", "5000"]

Este Dockerfile crea una imagen que se basa en la imagen de Alpine Node.js. Establece el directorio de trabajo, copia el archivo de dependencias y los instala, luego construye la aplicación y finalmente la sirve a través del paquete serve.

Para obtener una explicación línea por línea, consulte los documentos de Back4app Containers.

Esa imagen funciona, pero podemos optimizarla aprovechando las compilaciones de varias etapas. Las compilaciones de varias etapas nos permiten optimizar el tamaño de la imagen, simplificar el proceso de depuración, usar imágenes almacenadas en caché para acelerar el proceso de creación, etc.

Continúe y cree un nuevo archivo llamado Dockerfile en la raíz del proyecto con los siguientes contenidos:

FROM node:18-alpine as dependencies
WORKDIR /home/app

COPY package.json ./
COPY package-lock.json ./
RUN npm ci

# =====================================================================================

FROM node:18-alpine AS builder
WORKDIR /home/app

COPY --from=dependencies /home/app/node_modules ./node_modules
COPY . .

ENV NODE_ENV="production"

RUN npm run build

# =====================================================================================

FROM node:18-alpine AS runner
WORKDIR /home/app

COPY --from=builder /home/app/build ./build

RUN npm install -g serve

EXPOSE 3000
ENV PORT 3000

CMD ["serve", "-s", "build", "-l", "3000"]

Este Dockerfile tiene tres etapas:

  1.  dependencies que copia el archivo package.json e instala las dependencias
  2. El de builder que usa las dependencias de la etapa anterior para construir la imagen
  3. El de runner que toma la salida de la etapa builder y sirve a la aplicación

Al usar la compilación de varias etapas, reduciremos el tamaño de la imagen en aproximadamente un 40 % y aceleraremos considerablemente la compilación de imágenes.

.dockerignore

Nuestro proyecto contiene algunos archivos que no necesitamos en la compilación de producción, por ejemplo. node_modules, .git, etc. Para excluirlos de la imagen podemos usar un archivo.dockerignore.

Cree un archivo .dockerignore en la raíz del proyecto con el siguiente contenido:

.idea/
.git/

/node_modules
/.next/
/out/
/build

.env*.local
.vercel

Siéntase libre de modificarlo de acuerdo a sus necesidades.

Construir y probar

Antes de enviar sus imágenes a la nube, es una buena idea probarlas localmente. Para hacerlo, necesitará Docker Engine/Docker Desktop instalado. Primero, verifique su versión de Docker ejecutando:

$ docker --version

Docker version 20.10.22, build 3a2c30b

A continuación, cree y etiquete la imagen de react-pomodoro:

$ docker build -t react-pomodoro:1.0 .

Luego use la imagen recién creada para hacer girar un contenedor:

$ docker run -p 3000:3000 -d react-pomodoro:1.0

Explicación de los argumentos:

  1. -p abreviatura de –port vincula el puerto 3000 a 3000.
  2. -d abreviatura de -- detached ejecuta el contenedor en modo separado (fuera de la terminal)
  3. react-pomodoro:1.0 especifica qué imagen desea usar

Compruebe los contenedores en ejecución:

$ docker ps

Su aplicación ahora se ejecuta en un contenedor localmente. Asegúrese de que funcione navegando a http://localhost:3000 en su navegador web favorito.

Repositorio GitHub

Para implementar una aplicación en Back4app Containers, primero debe enviar su código fuente a GitHub. Puedes seguir estos pasos:

  1. Cree una cuenta en GitHub.
  2. Cree un nuevo repositorio de GitHub.
  3. Navegue a su proyecto local e inicialice el repositorio a través de git init.
  4. VCS todo el código fuente a través de git add. (puede usar un archivo .gitignore para ignorar archivos).
  5. Agregue el origen remoto a través de git remote add origin <remote_url>.
  6. Confirme el código a través de git commit -m “commit inicial”.
  7. Empuje el código a través de git push origin master.

Si nunca ha trabajado con Git, no dude en ver este video).

Implemente la aplicación

Para implementar una aplicación en Back4app Containers, primero deberá crear una cuenta.

Una vez que inicie sesión en su cuenta Back4app, será redirigido al panel de control de su aplicación. Haga clic en el botón “Crear nueva aplicación” para comenzar a crear su aplicación.

Back4app Create App

Back4app ofrece soluciones BaaS (Backend as a Service) y CaaS (Containers as a Service).Dado que estamos implementando un contenedor, seleccione “CaaS”.

Back4app Containers as a Service

A continuación, deberá vincular su cuenta de GitHub con Back4app e importar el repositorio que ha creado previamente.

Back4app Select Repository

Back4app Containers permite una configuración avanzada, pero para nuestra aplicación simple, solo necesitamos proporcionar el nombre de la aplicación. Una vez que haya ingresado el nombre de la aplicación, haga clic en “Implementar” para iniciar el proceso de implementación.

Back4app Configure App

Espere aproximadamente 5 minutos para que su aplicación se implemente. Una vez finalizada la implementación. Haga clic en el enlace verde del lado izquierdo de la pantalla para abrir la aplicación en su navegador.

Back4app Successfully Deployed

¡Eso es todo! Su aplicación ahora se implementó correctamente y se puede acceder a ella a través del enlace provisto. Además, puede notar que se puede acceder a su aplicación a través de HTTPS, ya que Back4app emitió automáticamente un certificado SSL gratuito para su aplicación.

Conclusión

React es una de las mejores bibliotecas JavaScript frontend de código abierto para crear interfaces de usuario. En este artículo, ha aprendido sobre sus ventajas, desventajas y cómo crear su propia aplicación React. Además de eso, ahora sabe cómo alojar una aplicación React en contenedores Back4app.

El código fuente final se puede encontrar en GitHub.

Preguntas frecuentes

¿Qué es React?

React es una biblioteca de JavaScript gratuita y de código abierto para crear interfaces de usuario interactivas. Fue creado por Meta en 2013 y actualmente es una de las bibliotecas de interfaz de usuario más populares. ¡Se puede usar para crear aplicaciones web, aplicaciones nativas, extensiones de navegador y más!

¿Cuáles son las ventajas de React?

– Rendimiento 
– Arquitectura basada en componentes 
– Fácil de aprender y fácil de usar 
– Multiplataforma 
– Gran comunidad

¿Cuáles son las desventajas de React?

– Alto ritmo de desarrollo 
– Dependencia de bibliotecas de terceros 
– Falta de convenciones 
– SEO 
– Lógica en las vistas

¿Cómo alojar una aplicación React?

1. Cree una aplicación React. 
2. Dockerize la aplicación usando un Dockerfile
3. Empuje el código fuente a GitHub.
4. Cree una cuenta en Back4app Containers
5. Configure el entorno y haga clic en “Implementar”.


Leave a reply

Your email address will not be published.