martes, 27 de mayo de 2025

Validar desde el servidor la introducción de datos al editar y actualizar un registro

app\Models\ContactoModel.php (Queda igual)

<?php

namespace App\Models;

use CodeIgniter\Model;

class ContactoModel extends Model
{
    protected $table = 'contactos';
    protected $primaryKey = 'id';
    protected $allowedFields = ['nombre', 'apellidos', 'celular'];

     protected $validationRules = [
        'nombre'    => 'required|min_length[3]',
        'apellidos' => 'required|min_length[3]',
        'celular'   => 'required|numeric|min_length[7]'
    ];

    protected $validationMessages = [
        'nombre'    => ['required' => 'El nombre es obligatorio.', 'min_length' => 'Debe tener al menos 3 caracteres.'],
        'apellidos' => ['required' => 'Los apellidos son obligatorios.', 'min_length' => 'Los apellidos debe tener al menos 3 caracteres.'],
        'celular'   => ['required' => 'El celular es obligatorio.', 'numeric' => 'El celular debe contener solo números.', 'min_length' => 'El celular debe tener al menos 7 dígitos.']
    ];
}

app\Controllers\Contacto.php (Extracto)

 public function actualizar($id)
    {
        $modelo = new ContactoModel();
        $data = [
            'id' => $id, 
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];


        if (!$modelo->update($id,$data)) {
        // Vuelve a mostrar el formulario con los errores y datos ingresados
        return view('contacto/editar', [
            'errors' => $modelo->errors(),
            'contacto' => $data
            ]);
        }
        return redirect()->to(MI_BASE_URL.'listar')->with('mensaje', 'Contacto actualizado exitosamente.');
    }

app\Views\contacto\editar.php

<h1>Editar Contacto</h1>

    <!-- Mostrar errores si existen -->
    <?php if (isset($errors) && !empty($errors)): ?>
        <div class="error">
            <ul>
                <?php foreach ($errors as $error): ?>
                    <li><?= esc($error) ?></li>
                <?php endforeach; ?>
            </ul>
        </div>
    <?php endif; ?>

<form action="<?= MI_BASE_URL.'actualizar/'.$contacto['id'] ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre" value="<?= $contacto['nombre'] ?>"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos" value="<?= $contacto['apellidos'] ?>"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular" value="<?= $contacto['celular'] ?>"><br><br>
    <input type="submit" value="Actualizar">
</form>

app\Views\contacto\listar.php

<h1>Listado de Contactos</h1>

 <?php if (session()->getFlashdata('mensaje')): ?>
        <p style="color:green"><?= session()->getFlashdata('mensaje') ?></p>
    <?php endif; ?>

<table>
    <tr>
        <th>Nombre</th>
        <th>Apellido</th>
        <th>Celular</th>
        <th>Acciones</th>
    </tr>
    <?php foreach ($contactos as $contacto) : ?>
    <tr>
        <td><?= $contacto['nombre'] ?></td>
        <td><?= $contacto['apellidos'] ?></td>
        <td><?= $contacto['celular'] ?></td>
        <td>
            <a href="<?= MI_BASE_URL.'editar/'.$contacto['id'] ?>">Editar</a>
            <a href="<?= MI_BASE_URL.'eliminar/'.$contacto['id'] ?>">Eliminar</a>
        </td>
    </tr>
    <?php endforeach ?>
</table>

domingo, 25 de mayo de 2025

Validar desde el servidor la introducción de datos al crear un nuevo registro

app\Models\ContactoModel.php

<?php

namespace App\Models;

use CodeIgniter\Model;

class ContactoModel extends Model
{
    protected $table = 'contactos';
    protected $primaryKey = 'id';
    protected $allowedFields = ['nombre', 'apellidos', 'celular'];

     protected $validationRules = [
        'nombre'    => 'required|min_length[3]',
        'apellidos' => 'required|min_length[3]',
        'celular'   => 'required|numeric|min_length[7]'
    ];

    protected $validationMessages = [
        'nombre'    => ['required' => 'El nombre es obligatorio.', 'min_length' => 'Debe tener al menos 3 caracteres.'],
        'apellidos' => ['required' => 'Los apellidos son obligatorios.', 'min_length' => 'Los apellidos debe tener al menos 3 caracteres.'],
        'celular'   => ['required' => 'El celular es obligatorio.', 'numeric' => 'El celular debe contener solo números.', 'min_length' => 'El celular debe tener al menos 7 dígitos.']
    ];
}

app\Controllers\Contacto.php (Extracto)

   public function guardar()
    {
        $modelo = new ContactoModel();
        $data = [
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];

        if (!$modelo->insert($data)) {
                return view('contacto/crear', [
                    'errors' => $modelo->errors(),
                    'old' => $data
                ]);
            }

        return redirect()->to(MI_BASE_URL.'crear')->with('mensaje', 'Contacto agregado correctamente.');
    }

app\Views\contacto\crear.php

<h1>Crear Contacto</h1>


    <?php if (session()->getFlashdata('mensaje')): ?>
        <p style="color:green"><?= session()->getFlashdata('mensaje') ?></p>
    <?php endif; ?>

    <?php if (isset($errors)): ?>
        <ul style="color:red">
            <?php foreach ($errors as $error): ?>
                <li><?= esc($error) ?></li>
            <?php endforeach; ?>
        </ul>
    <?php endif; ?>

    
<form action="<?= MI_BASE_URL.'guardar' ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular"><br><br>
    <input type="submit" value="Crear">
</form>

sábado, 24 de mayo de 2025

CRUD en CodeIgniter 4

app\Models\ContactoModel.php

<?php

namespace App\Models;

use CodeIgniter\Model;

class ContactoModel extends Model
{
    protected $table = 'contactos';
    protected $primaryKey = 'id';
    protected $allowedFields = ['nombre', 'apellidos', 'celular'];
}

app\Controllers\Contacto.php

<?php
namespace App\Controllers;

use App\Models\ContactoModel;

class Contacto extends BaseController
{
    public function index()
    {
        return view('menu');
    }

    public function listar()
    {
        $modelo = new ContactoModel();
        $data['contactos'] = $modelo->findAll();
        return view('contacto/listar', $data);
    }

    public function crear()
    {
        return view('contacto/crear');
    }

    public function guardar()
    {
        $modelo = new ContactoModel();
        $data = [
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];
        $modelo->insert($data);
        return redirect()->to(MI_BASE_URL.'listar');
    }

    public function editar($id)
    {
        $modelo = new ContactoModel();
        $data['contacto'] = $modelo->find($id);
        return view('contacto/editar', $data);
    }

    public function actualizar($id)
    {
        $modelo = new ContactoModel();
        $data = [
            'nombre' => $this->request->getPost('nombre'),
            'apellidos' => $this->request->getPost('apellidos'),
            'celular' => $this->request->getPost('celular'),
        ];
        $modelo->update($id, $data);
        return redirect()->to(MI_BASE_URL.'listar');
    }

    public function eliminar($id)
    {
        $modelo = new ContactoModel();
        $modelo->delete($id);
        return redirect()->to(MI_BASE_URL.'listar');
    }

}

app\Views\menu.php

<h1>Menú de Contactos</h1>

<ul>
    <li><a href="<?= MI_BASE_URL.'listar' ?> ">Listar Contactos</a></li>
    <li><a href="<?= MI_BASE_URL.'crear' ?> ">Crear Contacto</a></li>
</ul>

app\Views\contacto\crear.php

<h1>Crear Contacto</h1>

<form action="<?= MI_BASE_URL.'guardar' ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular"><br><br>
    <input type="submit" value="Crear">
</form>

app\Views\contacto\editar.php

<h1>Editar Contacto</h1>

<form action="<?= MI_BASE_URL.'actualizar/'.$contacto['id'] ?>" method="post">
    <label for="nombre">Nombre:</label>
    <input type="text" id="nombre" name="nombre" value="<?= $contacto['nombre'] ?>"><br><br>
    <label for="apellidos">Apellido:</label>
    <input type="text" id="apellidos" name="apellidos" value="<?= $contacto['apellidos'] ?>"><br><br>
    <label for="celular">Celular:</label>
    <input type="text" id="celular" name="celular" value="<?= $contacto['celular'] ?>"><br><br>
    <input type="submit" value="Actualizar">
</form>

app\Views\contacto\listar.php

<h1>Listado de Contactos</h1>

<table>
    <tr>
        <th>Nombre</th>
        <th>Apellido</th>
        <th>Celular</th>
        <th>Acciones</th>
    </tr>
    <?php foreach ($contactos as $contacto) : ?>
    <tr>
        <td><?= $contacto['nombre'] ?></td>
        <td><?= $contacto['apellidos'] ?></td>
        <td><?= $contacto['celular'] ?></td>
        <td>
            <a href="<?= MI_BASE_URL.'editar/'.$contacto['id'] ?>">Editar</a>
            <a href="<?= MI_BASE_URL.'eliminar/'.$contacto['id'] ?>">Eliminar</a>
        </td>
    </tr>
    <?php endforeach ?>
</table>

app\Config\Routes.php

<?php

use CodeIgniter\Router\RouteCollection;

/**
 * @var RouteCollection $routes
 */
$routes->get('/', 'Contacto::index');
$routes->get('/listar', 'Contacto::listar');
$routes->get('/crear', 'Contacto::crear');
$routes->post('/guardar', 'Contacto::guardar');
$routes->get('/editar/(:num)', 'Contacto::editar/$1');
$routes->post('/actualizar/(:num)', 'Contacto::actualizar/$1');
$routes->get('/eliminar/(:num)', 'Contacto::eliminar/$1');

Un tropiezo en el camino: base_url() y site_url()

Me encontraba creando la segunda aplicación web en CodeIgniter cuando me tropezé con base_url() en el contexto de usarla para llamar una pagina php o html, definido previamente con una ruta. Primero me producía error al cargar las páginas. Luego de verificar que no estaba mal la configuración de las rutas y de escribir manualmente el recurso solicitado en la barra de direcciones, llegué a la conclusión de que no estaba funcionando adecuadamente. Al intentar modificar el contenido de la función para que apuntara a la url correcta en el archivo de configuración correspondiente, observé como toda la aplicación estallaba catastroficamente. Entonces, decidí no tocarla para nada, ni a base_url() y tampoco a site_url() e implementar mi propia constante para tener la ruta correcta y que no reviente toda la aplicación. Así que lo que hice fue agregar las siguientes lineas al archivo app\Config\Constants.php en el que se define una cosntante llamada MI_BASE_URL:

 $miBaseURL = "http://".$_SERVER['HTTP_HOST'];
 $miBaseURL .= str_replace(basename($_SERVER['SCRIPT_NAME']),'', $_SERVER['SCRIPT_NAME']);
 defined('MI_BASE_URL')      || define('MI_BASE_URL',$miBaseURL);

Luego, se puede usar esta constante en donde se necesite llamar a cualquier recurso:

<a href="<?= MI_BASE_URL.'listar' ?> ">Listar Contactos</a>

viernes, 23 de mayo de 2025

Mi primera Aplicación Web con CodeIgniter 4: Mostrando registros de la tabla

app/Models/AgendaModel.php

<?php 
namespace App\Models;

use CodeIgniter\Model;

class AgendaModel extends Model
{
	protected $table = 'contactos';
	protected $primaryKey = 'id';
	protected $allowedFields = ['id','nombre','apellidos','celular'];

	public function getAll()
	{
		return $this->findAll();
	}
}

app/Controllers/AgendaController.php

<?php 
namespace App\Controllers;

use App\Models\AgendaModel;

class AgendaController extends BaseController
{
	public function index()
	{
		$AgendaModel = new AgendaModel();
		$data['agenda'] = $AgendaModel->getAll();
		return view('agenda',$data);
	}
}

app/Views/agenda.php

<h1>Agenda</h1>
<table>
	<thead>
		<tr>
			<th>Id</th>
			<th>Nombre</th>
			<th>Apellidos</th>
			<th>Celular</th>
		</tr>
	</thead>
	<tbody>
		<?php foreach($agenda as $item): ?>
			<tr>
				<td> <?= $item['id'] ?> </td>
				<td> <?= $item['nombre'] ?> </td>
				<td> <?= $item['apellidos'] ?> </td>
				<td> <?= $item['celular'] ?> </td>
			</tr>
		<?php endforeach ?>
	</tbody>
</table>

app/Config/Routes.php

$routes->get('/', 'AgendaController::index');

Creando y configurando la base de datos.

  • Desde phpMyAdmin crear una base de datos llamada agenda, dentro de esta una tabla llamada contactos y dentro de esta cuatro campos llamados id, nombre, apellidos y celular. establecer Id con el atributo de AUTO_INCREMENT y como clave principal.
  • Configurar los parametros de la base de datos. Dentro de la carpeta del proyecto de CodeIgniter, entrar a app/Config/database.php y establecer valores como el nombre de la base de datos, el usuario y la contraseña entre otros.

Creando manualmente un proyecto en CodeIgniter 4.6.1

  • Descargar el archivo zip.
  • Descomprimir y guardar en la carpeta htdocs de XAMP.
  • Establecer un nombre adecuado para la carpeta. En mi caso le voy a llamar agenda
  • Dentro de la carpeta renombrar el archivo env a .env. Dentro del archivo .env establecer el entorno de trabajo a desarrollo en vez de producción. Para ello se descomenta la linea # CI_ENVIRONMENT = production y se modifica para que quede así: CI_ENVIRONMENT = development
  • En este punto se puede probar que se ha iniciado el proyecto adecuadamente. Se inicia Apache y en la barra de direcciones del navegador se escribe localhost/agenda. Se ingresa a public y allí deberá aparecer el mensaje de bienvenida y en la parte de abajo un mensaje indicando que está en modo de desarrollo.

Instalando XAMP y dejando todo listo para empezar

  • Descargar XAMP for Windows.
  • Ejecutar el instalador como administrador.
  • Tal vez haya que modificar el UAC (User Account Control) pero en mi caso no tuve que hacer nada.
  • Desde el panel de control de XAMP abrir el archivo de configuración php.ini y activar la extensión intl.
  • Ejecutar el Servidor Apache y MySQL.
  • En la primera ejecución se pedirá permiso para que el firewall de windows no los bloquee.
  • Escribir en la barra de direcciones del navegador localhost para verificar que todo esté funcionando bien.

martes, 13 de mayo de 2025

Una nueva forma de crear aplicaciones webs ... para mi.

Me gusta mucho el lenguaje PHP, pero hasta ahora solo lo he usado en su versión estructurada y sin un framework. Es hora de iniciar un proceso para crear una app web usando herramientas más profesionales. Estas son:

  • XAMP for Windows 8.0.30
  • Codeigniter 4.6.1
  • Visual Studio Code

Agrupada bajo una misma etiqueta, la intención es ir registrando todo lo necesario para crear una aplicación web de manera más profesional y aplicando los mejores practicas de programación.

sábado, 19 de abril de 2025

Mejorar el rendimiento de computador con Windows 11

1. Desactivar programas que inician con Windows. Presionar Ctrl + Shift + Esc para abrir el Administrador de tareas, ir a la pestaña Aplicaciones de Arranque, revisar la columna Impacto de inicio y desactivar los que tengan Alto y no sean esenciales.

2. Desinstalar programas que no se usan. Ingresar a Configuración → Aplicaciones → Aplicaciones instaladas y eliminar programas que no se utilizan.

3. Presionar Tecla Windows + R para abrir el cuadro de dialogo Ejecutar. Escribir y ejecutar temp. Aparece la carpeta de archivos temporales de windows. A continuación se procede a borrar los archivos y carpetas temporales que aparezcan. Para ello se puede presionar CTRL + E para seleccionarlos y luego DEL o SUPR para enviarlos a la papelera de reciclaje.

4. De manera parecida al paso anterior, con la diferencia de que se va a ejecutar %temp%. Esta orden abre la carpeta de los archivos y carpetas temporales del usuario actual.

5. Se procede de la misma forma y se ejecuta prefetch. Esta carpeta almacena información sobre los programas que se usan con frecuencia para que se carguen más rápido al iniciarlos.

6. Usar la herramienta Liberador de espacio en disco.

lunes, 24 de febrero de 2025

Fabricar un prototipo de imprenta

  • Papel Foami liso tamaño carta color claro.
  • Tapas de gaseosa (12) del mismo tamaño.
  • Gota mágica (2).
  • hojas bloc papel carta sin raya.
  • Tijeras punta roma.
  • Esponja.
  • Tinta.
  • Guantes.

domingo, 9 de febrero de 2025

Crear abono para plantas a partir de residuos orgánicos

En vez de fabricar el compost directamente este metodo se centra en secar los residuos organicos para luego ser usados directamente en la planta. La razón de hacer esto está en evitar que se produzcan malos olores, en hacerlo rápidamente pero especialmente en evitar que en el proceso se formen jejenes.

  • Recolecta residuos orgánicos.
  • Cortarlos en pedazos pequeños.
  • Extender sobre una plancha o tabla los residuos previamente cortados y déjalos secar al sol hasta que queden totalmente crujientes.
  • Moler los residuos y guardalos en bolsa resellable para su uso.

miércoles, 4 de septiembre de 2024

Lugares para visitar en Bogotá y en los alrededores

1. MUSEO DEL ORO
Descripción: Museo arqueológico con colección de orfebrería prehispánica colombiana.
Entrada: $5.000 por persona
Sitio Web: https://www.banrepcultural.org/bogota/museo-del-oro/programe-su-visita
Observaciones:Desde este lugar se puede llegar a pie a otros museos y a la plaza de Bolívar.

2. MALOKA
Descripción: Maloka es un museo interactivo que fomenta la pasión por el aprendizaje partir de los lazos entre ciencia, tecnología, innovación y sociedad. Hay sala de exposición, cine-domo, cine 3D, laboratorios.
Entrada: Cada actividad tiene su precio. Por ejemplo: Recorrido Exploratorio $32.300, Laboratorios $21.000, Cine $13.900. Comprando una manilla sale un poco más cómodo.
Sitio Web: https://maloka.org/
Observaciones: Este museo está enfocado principalmente a niños y jóvenes que están en la escuela y a cualquiera amante de la ciencia.

3. JARDÍN BOTANICO JOSÉ CELESTINO MUTIS
Descripción: El Jardín Botánico es un centro de investigación distrital con énfasis en ecosistemas altoandinos y de páramo.
Entrada: Hay una tarifa entrada general nacionales de $6.000 y otras tarifas que se detallan en el sitio web.
Sitio Web: https://bogota.gov.co/mi-ciudad/cultura-recreacion-y-deporte/costo-de-entrada-al-jardin-botanico-de-bogota-2024
Observaciones: En este sitio se van a encontrar plantas... muchas, muchas plantas.

4. PARQUE DE DIVERSIONES MUNDO AVENTURA
Descripción: Parque donde el visitante puede disfrutar de la más completa y variada diversión con: Atracciones Mecánicas, Juegos de Destrezas y Escenarios Naturales.
Entrada: Los precios varían de acuerdo a las actividades que se quieran realizar. Se pueden comprar pasaportes para varias actividades con precios de $55.000 en adelante.
Sitio Web: https://mundoaventura.com.co/planea-tu-visita/precios/
Observaciones: No he ido pero me cuentan que es bastante parecido a las llamadas ciudades de hierro, pero con más cosas. Está enfocado a la diversión y actividades extremas.

5. PARQUE SALITRE MÁGICO
Descripción: Parque de atracciones mecánicas, igual que mundo aventura.
Entrada: Los precios varían de acuerdo a las actividades que se quieran realizar. Se pueden comprar pasaportes para varias actividades con precios de $50.000 en adelante.
Sitio Web: https://salitremagico.com.co/
Observaciones: Tiene una temática parecida a Mundo aventura.

6. PARQUE METROPOLITANO SIMÓN BOLIVAR
Descripción: Área verde urbana con recorridos para caminantes y ciclistas, lago para andar en bote y un área de juego. Entrada: Gratis.
Sitio Web: https://www.idrd.gov.co/parques/parques-estructurantes/parque-metropolitano-simon-bolivar
Observaciones: En el 2013 llegamos a este lugar después de hacer un recorrido y regresar a Facatativá. Es un espacio público para caminar o hacer ejercicios. Allí se realizan conciertos.

7. PARQUE JAIME DUQUE
Descripción: Parque temático de enfoque familiar.
Entrada: Los precios varían de acuerdo a las actividades que se quieran realizar. Se pueden comprar pasaportes para varias actividades con precios de $52.000 en adelante.
Sitio Web: https://parquejaimeduque.com/
Observaciones: Se encuentra fuera de Bogotá, a una hora en transporte terrestre.

8. CERRO DE MONSERRATE
Descripción: Es una montaña a la cual se puede subir a pie, en funicular y en teleférico. En su parte alta hay una iglesia, restaurantes y un mirador de la ciudad.
Entrada: Subir a pie no tiene costo. Funicular o Teleférico Ida y Vuelta Desde $29.500
Sitio Web: https://monserrate.co/
Observaciones: Se encuentra cerca del centro de Bogotá.

9. MUSEO BOTERO
Descripción: El Museo Botero cuenta con una de las más importantes colecciones de arte internacional que se puedan encontrar en Latinoamérica.
Entrada: Gratis.
Sitio Web: https://www.banrepcultural.org/bogota/museo-botero
Observaciones: Se encuentra cerca del museo del oro.

10. MUSEO NACIONAL DE COLOMBIA
Descripción: Ofrece a sus visitantes diecisiete salas de exposición permanente, en las cuales se exhiben alrededor de 2.500 obras y objetos, símbolos de la historia y el patrimonio nacional.
Entrada: Adultos $6.000 .
Sitio Web: https://www.museonacional.gov.co/
Observaciones: Para los amantes de la historia de Colombia.

11. A continuación les comparto información sobre el Parque Arqueológico Piedras del Tunjo en Facatativá:
Tarifas: Nacionales colombianos $13.500; Extranjeros $65.000 (Temprano en la mañana el parque está abierto al público de manera gratuita)
Sitio Web: http://www.colparques.net/FACA

Otros lugares: El planetario, la casa museo Simón Bolivar, Tren turistico de la sabana: Turistren.

viernes, 21 de junio de 2024

jueves, 20 de junio de 2024

Fabricación de un biodigestor casero didáctico

El objetivo de esta actividad era crear un biodigestor pequeño pero funcional. Una vez terminado y habiendo comprobado su funcionamiento se les darían las instrucciones a los estudiantes para que ellos construyan el suyo y puedan producir su propio biogas.

Prototipo 1.0

Se usó excremento de vaca disuelto en agua. El primer prototipo parecía prometedor. Sin embargo, algo ocurría: en cuanto empezaba a llenarse el globo perdía presión.

Prototipo 2.0

El segundo prototipo tenía como objetivo determinar la razón por la que había la perdida de gas. Sospechaba que la tubería quedaba con agujeros. Me dí cuenta de que el pico de la botella rasgaba el globo.

Prototipo 3.0

Para evitar el problema anterior se construyó el tercer prototipo. Un examen cuidadoso arrojó donde estaba el problema: el globo tenía agujeros muy pequeños. Entonces no se podía usar globos para almacenar el biogas. En vez de globo se usó una bolsa plástica. Debido a que no se aseguró bien al tubo había perdida de presión.

Prototipo 4.0

El prototipo cuatro es la primera versión funcional. Se había asegurado bien la bolsa para que no hubiese perdida de presión. La bolsa se llenó de biogas después de unos cuantos días. Cuando se hizo la prueba el biogás ardió por unos pocos segundos.

lunes, 6 de mayo de 2024

Mi nuevo autor favorito

Si alguna vez alguien ha estado siguiendo las entradas a este blog ya habrá notado que me encanta la ciencia ficción. Hace aproximadamente seis meses (no recuerdo cómo, ni por que) empecé a escuchar en audiolibros los cuentos y novelas del escritor Isaac Asimov. Simplemente he quedado encantado con las historias de ciencia ficción. Un cuento que me ha llamado mucho la atención es Una estatua para papá.

Quiero mencionar que en especial "me enganché" en escuchar en audiolibro las novelas de Serie de la fundación. El siguiente cuadro resume el orden en que fueron apareciendo. Además es el orden en el que suguiero que se vayan leyendo. No están totalmente en orden cronologico. Algo que me ha encantado son los giros inesperados en las historias: cuando uno se espera algo y luego resulta que todo el tiempo el autor nos ha tenido engañado. En el libro Fundación y tierra he notado un ligero cambio, que me ha incomodado, en la forma como se ha venido contando la historia y al final quedo cómo diciendo "¿Qué ha pasado aquí? Pero en general me ha encantado la serie.

Asimov creó otras novelas que tambien están organizadas en series, como La serie de los robots o La serie del imperio galáctico que existen en el mismo universo de la fundación.

Quedan para el recuerdo algunas ilustraciones que he encontrado acerca de escenas de las novelas y que evocan aventuras o situaciones vividas por los personajes.

viernes, 29 de marzo de 2024

Star trek

No me considero un fanático de esta franquicia, solo he visto la mayoría de peliculas y series, algunas me disgustan, otras me gustan y otras me encantan. Pero puedo decir que es la mejor franquicia de ciencia ficción y aventuras que existe y está en vigencia por el momento.

Voyager fue la primera serie de Star trek que vi completa. Ya había visto de niño algunos episodios de La nueva generación pero no me habían llamado demasiado la atención. Sin embargo, esta serie me enamoró de la franquicia.

Esta pelicula del 2009 fue concebida para atraer al público joven a la franquicia. A mi me encantó y me hizo querer ver más.

Sin embargo, a mi parecer la mejor pelicula de todas es Primer Contacto ¿Que tiene de especial? Por un lado una trama cautivadora, ha envejecido muy bien y sus antagonistas: Los Borg.