Tecnologias de la Información y la Comunicación

El verdadero progreso es el que pone la tecnología al alcance de todos". (Henry Ford)

Software

"Si piensas que los usuarios de tus programas son idiotas, sólo los idiotas usarán tus programas". Linus Torvalds - "padre" de Linux

Hardware

El hardware es para el informático como la barita mágica del mago, pero un poco más caro. "El ordenador elige al dueño..."

Seguridad informática

El único sistema seguro es aquél que está apagado en el interior de un bloque de hormigón protegido en una habitación sellada rodeada por guardias armados.

Realidad virtual

Desde tiempos inmemorables nos empeñamos más en crear mundos que vivir el nuestro.

Mostrando entradas con la etiqueta Tutoriales. Mostrar todas las entradas
Mostrando entradas con la etiqueta Tutoriales. Mostrar todas las entradas

martes, 7 de febrero de 2017

Angular JS: qué es y cómo crear tu primera aplicación

Artículo original de Toptal. Click aquí para verlo y aquí para leer la versión original en inglés.

¿Qué es AngularJS?

AngularJS es un marco de JavaScript MVC desarrollado por Google, el cual permite construir aplicaciones front-end bien estructuradas y fáciles de comprobar y mantener.

¿Y Por Qué Debo Utilizarlo?

Si no has probado AngularJS todavía, es una lástima. El marco consiste en un conjunto de herramientas bien integradas que te ayudará a construir aplicaciones del lado del cliente, bien estructuradas en un sistema modular, con menos código y más flexibilidad.
AngularJS extiende HTML, proporcionando directrices que añaden funcionalidad a tu margen de beneficio y te permite crear plantillas dinámicas poderosas. También puedes crear tus propias directrices, elaborando componentes reusables que completan tus necesidades y abstrayendo toda la lógica de manipulación del DOM.
También implementa binding de datos de dos vías, conectando tu HTML (vistas) a los objetos de JavaScript (modelos) sin problemas. En términos simples, esto significa que cualquier actualización de tu modelo se reflejará inmediatamente en tu vista, sin necesidad de ningún tipo de manipulación DOM o el control de eventos (por ejemplo, con jQuery).
Angular presta servicios en la parte superior de XHR que simplifican considerablemente tu código y permite abstraer llamadas API en servicios reusables. Con esto, puedes mover tu modelo y lógica de negocio para el front-end y construir aplicaciones web back-end independientes (agnostic).
Por último, me encanta Angular debido a su flexibilidad en cuanto a la comunicación del servidor. Como la mayoría de los marcos de JavaScript MVC, Angular te permite trabajar con cualquier tecnología de servidor, siempre que puede servir a tu aplicación a través de una API REST Web. Pero Angular también proporciona servicios aparte de XHR, los cuales simplifican considerablemente tu código y te permite abstraer llamadas API en servicios reusables. Como resultado, se puede mover el modelo y la lógica de negocio para el front-end y construir aplicaciones web back-end independientes. En este post vamos a hacer precisamente eso: un paso a la vez.

Así que, ¿Por Dónde Empezamos?

En primer lugar, vamos a decidir la naturaleza de la aplicación que queremos construir. En esta guía, preferimos no pasar demasiado tiempo en el back-end, por lo que vamos a escribir algo sobre la base de datos que es fácil de obtener en internet, ¡como una aplicación de noticias deportiva!
Ya que soy un gran fan del automovilismo y la Fórmula 1, voy a utilizar un servicio API Autosport como nuestro back-end. Por suerte, los chicos de Ergast son lo suficientemente amables para proporcionar una API de automovilismo gratis, la cual es perfecta para nosotros.
Como adelanto de lo que vamos a construir, echa un vistazo al demo en vivo. Para embellecer el demo y mostrar algunas plantillas Angular, apliqué un tema Bootstrap de WrapBootstrap, pero ya que éste artículo no es acerca de CSS, lo voy a abstraer de los ejemplos y dejarlo fuera por completo.

Tutorial para Comenzar

Vamos a iniciar nuestra aplicación de ejemplo con un poco de Boilerplate. Recomiendo el proyecto angular-seed, ya que no sólo proporciona un gran esqueleto para bootstrapping, sino que también establece las bases para las pruebas de unidad con Karma y Jasmine(no vamos a hacer ninguna prueba en éste demo, así que vamos dejar eso de lado por ahora; ve la Parte 2 de éste tutorial para obtener más información sobre la configuración de tu proyecto, para pruebas unitarias y de extremo a extremo).

EDITADO (Mayo de 2014): Desde que escribí éste tutorial, el proyecto angular-seed ha pasado por algunos cambios importantes (incluyendo la adición de Bower como gestor de paquetes). Si tienes alguna duda acerca de cómo implementar el proyecto, echa un vistazo rápido a la primera sección de su guía de referencia. En la parte 2 del tutorial, Bower, entre otras herramientas, es explicado en mayor detalle.

Bien, ahora que hemos clonado el repositorio e instalado las dependencias, el esqueleto de nuestra aplicación va a tener este aspecto:
Ahora podemos empezar a codificar. Como estamos tratando de construir aplicación de noticias de deporte para un campeonato de carreras, vamos a empezar con la vista más relevante: la tabla del campeonato.
Teniendo en cuenta que ya tenemos una lista de los conductores definida dentro de nuestro alcance (Quédate conmigo – Llegaremos ahí), y haciendo caso omiso de cualquier CSS (para facilitar la lectura), nuestra HTML podría ser:
<body ng-app="F1FeederApp" ng-controller="driversController">
  <table>
    <thead>
      <tr><th colspan="4">Drivers Championship Standings</th></tr>
    </thead>
    <tbody>
      <tr ng-repeat="driver in driversList">
        <td>{{$index + 1}}</td>
        <td>
          <img src="img/flags/{{driver.Driver.nationality}}.png" />
          {{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}}
        </td>
        <td>{{driver.Constructors[0].name}}</td>
        <td>{{driver.points}}</td>
      </tr>
    </tbody>
  </table>
</body>
La primera cosa que notarás en esta plantilla es el uso de expresiones (“{{“ y “}}”) para regresar valores de las variables. En AngularJS, las expresiones permiten ejecutar algunos cálculos, con el fin de regresar un valor deseado. Algunas expresiones válidas serían:
  • {{ 1 + 1 }}
  • {{ 946757880 | date }}
  • {{ user.name }}
Efectivamente, las expresiones son fragmentos parecidos a JavaScript. A pesar de ser muy potente, no deberías utilizar expresiones para implementar cualquier lógica de nivel superior. Para ello, utilizamos directrices.

La Comprensión de las Directrices Básicas

La segunda cosa que notarás es la presencia de ng-attributes, que no verías en el marcado típico. Esas son las directrices.
En un nivel alto, las directrices son marcadores (como atributos, etiquetas y nombres genéricos) que le ordenan a AngularJS adjuntar un comportamiento dado a un elemento DOM (o transformarlo, reemplazarlo, etc.). Vamos a echar un vistazo a los que ya hemos visto:
  • La directriz ng-app es responsable de hacer bootstrapping a tu aplicación, para definir el ámbito de ésta. En AngularJS, puedes tener múltiples aplicaciones dentro de la misma página, por lo que esta directriz define el lugar donde comienza y termina cada aplicación.
  • La directriz ng-controller define qué controlador estará a cargo de tu vista. En este caso, la denotamos driversController, la cual proporcionará nuestra lista de conductores (driversList).
  • La directriz ng-repeat es una de las más utilizadas, y sirve para definir tu alcance de plantilla al pasar a través de colecciones. En el ejemplo anterior, repite una línea en la tabla por cada conductor en driversList.

Añadir Controladores

Por supuesto, nuestra vista no sirve de nada, sin un controlador. Vamos a añadir driversController a nuestros controllers.js:
angular.module('F1FeederApp.controllers', []).
controller('driversController', function($scope) {
    $scope.driversList = [
      {
          Driver: {
              givenName: 'Sebastian',
              familyName: 'Vettel'
          },
          points: 322,
          nationality: "German",
          Constructors: [
              {name: "Red Bull"}
          ]
      },
      {
          Driver: {
          givenName: 'Fernando',
              familyName: 'Alonso'
          },
          points: 207,
          nationality: "Spanish",
          Constructors: [
              {name: "Ferrari"}
          ]
      }
    ];
});
Seguro notaste la variable $scope que estamos pasando como parámetro al controlador. La variable $scope se supone que debe enlazar tu controlador y vistas. En particular, lleva todos los datos que se utilizarán dentro de la plantilla. Todo lo que se agrega a ella (como la driversList del ejemplo anterior) será directamente accesible en tus vistas. Por ahora, vamos a trabajar con una matriz de datos ficticios (estática), que vamos a sustituir más tarde con nuestro servicio API.
Ahora, añade esto a app.js:
angular.module('F1FeederApp', [
  'F1FeederApp.controllers'
]);
Con esta línea de código inicializamos nuestra aplicación y registramos los módulos de los cuales depende. Volveremos a ese archivo (app.js) más adelante.
Ahora, vamos a poner todo junto en index.html:
<!DOCTYPE html>
<html>
<head>
  <title>F-1 Feeder</title>
</head>

<body ng-app="F1FeederApp" ng-controller="driversController">
  <table>
    <thead>
      <tr><th colspan="4">Drivers Championship Standings</th></tr>
    </thead>
    <tbody>
      <tr ng-repeat="driver in driversList">
        <td>{{$index + 1}}</td>
        <td>
          <img src="img/flags/{{driver.Driver.nationality}}.png" />
          {{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}}
        </td>
        <td>{{driver.Constructors[0].name}}</td>
        <td>{{driver.points}}</td>
      </tr>
    </tbody>
  </table>
  <script src="bower_components/angular/angular.js"></script>
  <script src="bower_components/angular-route/angular-route.js"></script>
  <script src="js/app.js"></script>
  <script src="js/services.js"></script>
  <script src="js/controllers.js"></script>
</body>
</html>
Moduló errores menores, ahora puedes iniciar tu aplicación y comprobar tu lista (estática) de los conductores.

Nota: Si necesitas ayuda para la depuración de la aplicación y la visualización de tus modelos y con el alcance dentro del navegador, recomiendo echar un vistazo a la impresionante batarang; complemento para Chrome.

Cargando Datos del Servidor

Como ya sabemos cómo mostrar los datos de nuestro controlador en nuestra vista, es momento de traer datos en vivo desde un servidor RESTful.
Para facilitar la comunicación con los servidores HTTP, AngularJS proporciona los servicios $http y $resource. El primero es una capa en la parte superior de XMLHttpRequest o JSONP, mientras que el último proporciona un mayor nivel de abstracción. Vamos a utilizar $http.
Para abstraer nuestras llamadas a la API del servidor desde el controlador vamos a crear nuestro propio servicio personalizado, el cual va a capturar los datos y actuará como una envoltura alrededor de $http al añadirlo a nuestro services.js:
angular.module('F1FeederApp.services', []).
  factory('ergastAPIservice', function($http) {

    var ergastAPI = {};

    ergastAPI.getDrivers = function() {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK'
      });
    }

    return ergastAPI;
  });
Con las dos primeras líneas, creamos un nuevo módulo (F1FeederApp.services) y registramos un servicio dentro de ese módulo (F1FeederApp.services). Nótese que pasamos $http como parámetro a ese servicio. Esto le dice al motor de inyección de dependenciade Angular, que nuestro nuevo servicio requiere (o depende) del servicio $http.
De una manera similar, tenemos que decirle a Angular que incluya nuestro nuevo módulo en nuestra aplicación. Vamos a registrarlo con app.js, reemplazando nuestro código existente con:
angular.module('F1FeederApp', [
  'F1FeederApp.controllers',
  'F1FeederApp.services'
]);
Ahora, lo único que tenemos que hacer es ajustar nuestra controller.js un poco, integrar ergastAPIservice como una dependencia, y estaremos listos para continuar:
angular.module('F1FeederApp.controllers', []).
  controller('driversController', function($scope, ergastAPIservice) {
    $scope.nameFilter = null;
    $scope.driversList = [];

    ergastAPIservice.getDrivers().success(function (response) {
        //Dig into the responde to get the relevant data
        $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings;
    });
  });
Ahora, recarga la aplicación y revisa el resultado. Observa que no hicimos ningún cambio en nuestra plantilla, pero añadimos una variable nameFilter a nuestro alcance. Vamos a poner esta variable en uso.

Filtros

¡Estupendo! Tenemos un controlador funcional. Pero sólo muestra una lista de conductores. Vamos a añadir algunas funciones mediante una simple entrada de búsqueda de texto, que filtrará la lista. Vamos a añadir la siguiente línea a nuestro index.html, justo debajo de la etiqueta <body>:
<input type="text" ng-model="nameFilter" placeholder="Search..."/>
Ahora estamos haciendo uso de la directriz ng-model. Esta directriz une nuestro campo de texto a la variable $scope.nameFilter y se asegura de que su valor esté siempre al día con el valor de entrada. Ahora, vamos a visitar index.html una vez más y hagamos un pequeño ajuste en la línea que contiene la directriz ng-repeat:
<tr ng-repeat="driver in driversList | filter: nameFilter">
Esta línea le dice a ng-repeat que, antes de dar salida a los datos, la matriz driversList debe ser filtrada por el valor almacenado en nameFilter.
En este punto, entran los datos bidireccionales binding: cada vez que un valor se introduce en el campo de búsqueda, Angular asegura inmediatamente que el $scope.nameFilter que asociamos a él se actualice con el nuevo valor. Dado que binding funciona en ambos sentidos, el momento en el que el valor nameFilter se actualiza, la segunda directriz asociada a la misma (es decir, ng-repeat) también recibe el nuevo valor y la vista se actualiza inmediatamente.
Actualiza la aplicación y observa la barra de búsqueda.
Observa que éste filtro buscará la palabra clave en todos los atributos del modelo, incluyendo los que no estamos usando. Digamos que sólo queremos filtrar Driver.givenName y Driver.familyName: En primer lugar, añadimos a driversController, justo por debajo de la línea $scope.driversList =[];:
$scope.searchFilter = function (driver) {
    var keyword = new RegExp($scope.nameFilter, 'i');
    return !$scope.nameFilter || keyword.test(driver.Driver.givenName) || keyword.test(driver.Driver.familyName);
};
Ahora, de vuelta a index.html, actualizamos la línea que contiene la directriz ng-repeat:
<tr ng-repeat="driver in driversList | filter: searchFilter">
Actualiza la aplicación una vez más y ahora tenemos una búsqueda por nombre.

Rutas

Nuestro próximo objetivo es crear una página de datos del conductor, la cual nos permitirá hacer clic en cada conductor y ver los detalles de su carrera.
En primer lugar, vamos a incluir el servicio $routeProvider (en app.js) lo que nos ayudará a lidiar con estas variadas rutas de aplicación. A continuación, añadiremos dos de estas rutas: una para la tabla del campeonato y otro para los datos del conductor. Aquí está nuestra nueva app.js:
angular.module('F1FeederApp', [
  'F1FeederApp.services',
  'F1FeederApp.controllers',
  'ngRoute'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.
 when("/drivers", {templateUrl: "partials/drivers.html", controller: "driversController"}).
 when("/drivers/:id", {templateUrl: "partials/driver.html", controller: "driverController"}).
 otherwise({redirectTo: '/drivers'});
}]);
Con éste cambio, la navegación hacia http://domain/#/drivers cargará el driversController y buscará la vista parcial que se va a renderizar en partials/drivers.html. ¡Pero espera! No tenemos ninguna vista parcial todavía, ¿verdad? Vamos a tener que crearlas también.

Vistas Parciales

AngularJS te permitirá unir tus rutas a los controladores y vistas específicas.
Pero primero, tenemos que decirle a Angular dónde renderizar estas vistas parciales. Para ello, usaremos la directriz ng-view, modificando nuestra index.html para reflejar lo siguiente:
<!DOCTYPE html>
<html>
<head>
  <title>F-1 Feeder</title>
</head>

<body ng-app="F1FeederApp">
  <ng-view></ng-view>
  <script src="bower_components/angular/angular.js"></script>
  <script src="bower_components/angular-route/angular-route.js"></script>
  <script src="js/app.js"></script>
  <script src="js/services.js"></script>
  <script src="js/controllers.js"></script>
</body>
</html>
Ahora, cada vez que naveguemos a través de nuestras rutas de aplicaciones, Angular cargará la vista asociada y la renderizará en lugar de la etiqueta <ng-view>. Lo único que tenemos que hacer es crear un archivo con el nombre partials/drivers.html, y poner nuestra tabla de campeonato HTML allí. También vamos a utilizar esta oportunidad para vincular el nombre del conductor a nuestra ruta de los detalles del conductor:
<input type="text" ng-model="nameFilter" placeholder="Search..."/>
<table>
<thead>
  <tr><th colspan="4">Drivers Championship Standings</th></tr>
</thead>
<tbody>
  <tr ng-repeat="driver in driversList | filter: searchFilter">
 <td>{{$index + 1}}</td>
 <td>
   <img src="img/flags/{{driver.Driver.nationality}}.png" />
    <a href="#/drivers/{{driver.Driver.driverId}}">
         {{driver.Driver.givenName}}&nbsp;{{driver.Driver.familyName}}
      </a>
    </td>
   <td>{{driver.Constructors[0].name}}</td>
   <td>{{driver.points}}</td>
  </tr>
</tbody>
</table>
Por último, vamos a decidir lo que queremos mostrar en la página de detalles. ¿Qué tal un resumen de todos los hechos relevantes sobre el conductor (por ejemplo, fecha de nacimiento, nacionalidad), junto con una tabla que contiene sus resultados recientes? Para hacer eso, añadimos a services.js, lo siguiente:
angular.module('F1FeederApp.services', [])
  .factory('ergastAPIservice', function($http) {

    var ergastAPI = {};

    ergastAPI.getDrivers = function() {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK'
      });
    }

    ergastAPI.getDriverDetails = function(id) {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/driverStandings.json?callback=JSON_CALLBACK'
      });
    }

    ergastAPI.getDriverRaces = function(id) {
      return $http({
        method: 'JSONP', 
        url: 'http://ergast.com/api/f1/2013/drivers/'+ id +'/results.json?callback=JSON_CALLBACK'
      });
    }

    return ergastAPI;
  });
Esta vez, proporcionamos la identificación del conductor al servicio para que podamos recuperar la información relevante de un conductor específico. Ahora, modificamos controllers.js:
angular.module('F1FeederApp.controllers', []).

  /* Drivers controller */
  controller('driversController', function($scope, ergastAPIservice) {
    $scope.nameFilter = null;
    $scope.driversList = [];
    $scope.searchFilter = function (driver) {
        var re = new RegExp($scope.nameFilter, 'i');
        return !$scope.nameFilter || re.test(driver.Driver.givenName) || re.test(driver.Driver.familyName);
    };

    ergastAPIservice.getDrivers().success(function (response) {
        //Digging into the response to get the relevant data
        $scope.driversList = response.MRData.StandingsTable.StandingsLists[0].DriverStandings;
    });
  }).

  /* Driver controller */
  controller('driverController', function($scope, $routeParams, ergastAPIservice) {
    $scope.id = $routeParams.id;
    $scope.races = [];
    $scope.driver = null;

    ergastAPIservice.getDriverDetails($scope.id).success(function (response) {
        $scope.driver = response.MRData.StandingsTable.StandingsLists[0].DriverStandings[0]; 
    });

    ergastAPIservice.getDriverRaces($scope.id).success(function (response) {
        $scope.races = response.MRData.RaceTable.Races; 
    }); 
  });
Lo importante a notar aquí es que solo inyectamos el servicio $routeParams en el controlador del conductor. Este servicio nos permitirá acceder a nuestros parámetros de URL (para el :id, en este caso) utilizando $routeParams.id.
Ahora que tenemos nuestros datos en el alcance, sólo necesitamos la vista parcial restante. Vamos a crear un archivo con el nombre partials/driver.html y agregamos:
<section id="main">
  <a href="./#/drivers"><- Back to drivers list</a>
  <nav id="secondary" class="main-nav">
    <div class="driver-picture">
      <div class="avatar">
        <img ng-show="driver" src="img/drivers/{{driver.Driver.driverId}}.png" />
        <img ng-show="driver" src="img/flags/{{driver.Driver.nationality}}.png" /><br/>
        {{driver.Driver.givenName}} {{driver.Driver.familyName}}
      </div>
    </div>
    <div class="driver-status">
      Country: {{driver.Driver.nationality}}   <br/>
      Team: {{driver.Constructors[0].name}}<br/>
      Birth: {{driver.Driver.dateOfBirth}}<br/>
      <a href="{{driver.Driver.url}}" target="_blank">Biography</a>
    </div>
  </nav>

  <div class="main-content">
    <table class="result-table">
      <thead>
        <tr><th colspan="5">Formula 1 2013 Results</th></tr>
      </thead>
      <tbody>
        <tr>
          <td>Round</td> <td>Grand Prix</td> <td>Team</td> <td>Grid</td> <td>Race</td>
        </tr>
        <tr ng-repeat="race in races">
          <td>{{race.round}}</td>
          <td><img  src="img/flags/{{race.Circuit.Location.country}}.png" />{{race.raceName}}</td>
          <td>{{race.Results[0].Constructor.name}}</td>
          <td>{{race.Results[0].grid}}</td>
          <td>{{race.Results[0].position}}</td>
        </tr>
      </tbody>
    </table>
  </div>

</section>
Observa que ahora estamos dándole buen uso a la directriz ng-show. Esta directriz sólo mostrará el elemento HTML si la expresión proporcionada es true (es decir, ni false, ni null). En este caso, el avatar sólo aparecerá una vez que el objeto conductor ha sido cargado en el alcance, por el controlador.

Últimos Toques

Añade un montón de CSS y renderiza tu página. Deberías terminar con algo como esto:
Ahora estás listo para iniciar tu aplicación y asegúrate de que ambas rutas están funcionando como deseas. También puedes añadir un menú estático a index.html, para mejorar las capacidades de navegación del usuario. Las posibilidades son infinitas.

EDITADO (mayo de 2014): He recibido muchas peticiones para una versión descargable del código que construimos en este tutorial. Por lo tanto, he decidido hacerlo disponible aquí (despojado de cualquier CSS). Sin embargo, la verdad es que no recomiendo descargarlo, ya que ésta guía contiene cada paso que necesitas para generar la misma aplicación con tus propias manos, que será un ejercicio de aprendizaje mucho más útil y eficaz.

Conclusión

En este punto del tutorial, hemos cubierto todo lo que necesitarías para escribir una aplicación sencilla (como un informador de Fórmula 1). Cada una de las páginas restantes en el demo en vivo (por ejemplo, tabla del campeonato de constructores, detalles del equipo, calendario) comparten la misma estructura y conceptos básicos que hemos revisado.
Por último, ten en cuenta que Angular es un marco muy potente y que apenas hemos tocado la superficie, en términos de todo lo que tiene que ofrecer. En la parte 2 de éste tutorial, vamos a dar ejemplos de por qué Angular se destaca entre sus semejantes en marcos MVC front-end: capacidad de prueba. Vamos a revisar el proceso de escribir y ejecutar pruebas unitarias con Karma, lograr la integración continua con Yeomen, Grunt, y Bower y otros puntos fuertes de éste fantástico marco front-end.

Artículo original de Toptal.com

jueves, 19 de enero de 2017

Chromecast: qué es, cómo se usa y cómo sacarle partido

Muchos de vosotros puede que tengáis un chromecast en vuetra casa (o varios, como yo). Otros no lo tendréis y alguno incluso no ha oído hablar todavía de este magnífico invento.


¿Qué es Google Chromecast?

De forma rápida: es un aparato que permite ver contenido por streaming en tu televisión, ya sea desde Youtube o cualquier url y también de contenido local desde un ordenador, Tablet o Smartphone.

Este chisme se conecta vía hdmi a tu televisor y se alimenta mediante un cable microusb. Se conecta a tu router y reproduce lo que tú le digas. “Pero esque yo tengo una Smart tv con la app de youtube” dirán algunos. Ya, pero este dispositivo te permite, por ejemplo, conectarte a streamcloud o powvideo y otros muchos tipos de servidores para ver tus series favoritas sin necesidad de aplicación para smartv y con conexión directa. Y lo manejas desde tu dispositivo móvil.
 
“Ah, entonces lo que haces es hacer un mirroring desde el móvil”. No. Bueno, puedes hacerlo, pero lo que más me gusta de este pequeñín es que se conecta directamente al servidor. Me explico: tú le dices que vídeo quieres ver de youtube y el chromecast se conecta a youtube y te muestra el vídeo. 

Desde el móvil puedes adelantarlo, atrasarlo, cambiar la calidad y todo lo que youtube siempre nos permite, pero no, no es un simple streaming de la pantalla de tu móvil. Esto significa que puedes dejarle a tus hijos la película de los Minions mientras tú estás en la cocina preparando una receta leyéndola en tu móvil porque, repito, NO ES UN STREAMING O MIRRORING DE LA PANTALLA DE TU MÓVIL.

¿Cómo se usa?

Para usar un chromecast primero debes conectarlo. ¿Cómo? A una entrada HDMI de tu televisor. 

Para alimentarlo trae un cable microusb como el de cualquier móvil. Mucha gente lo conecta al enchufe, pero mi recomendación es que lo conectes a un puerto usb de tu televisor (si lo tiene) ¿Por qué? Muy simple: porque si lo tienes enchufado en una regleta va a estar encendido 24 horas al día 365 días al año, a menos que lo desenchufes o sea una regleta con interruptor. Pero si lo conectas al usb del televisor se apagará cuando la televisión se apague y, cuando enciendas el televisor, se encenderá automáticamente. Creo que es la mejor forma.
 
Cuando tengas el aparato en tu televisor lo que debes hacer es cambiar el input al hdmi en el que hayas conectado el dispositivo y ya verás como aparece su fondo de pantalla. Pero todavía no puede conectarse a nada.

A continuación debes bajarte la aplicación Google Home. Al principio dicha app se llamaba Google Chromecast, después pasó a llamarse Google Cast y ahora se llama Google Home. Esta aplicación conectará tu Smartphone de forma directa con el chromecast recién estrenado. Es importante que sepas que este proceso solo se realiza la primera vez que se enciende el chromecast, por tanto, cuando termines de configurarlo, podrás desinstalar la aplicación de tu móvil. La primera conexión entre el Smartphone y el chromecast es directa mediante wifi, lo que significa que, mientras dure esta primera configuración, perderás la conexión a tu router wifi y no tendrás acceso a internet. Lo que harás a continuación será indicarle cuál es tu red wifi y la contraseña de conexión y, cuando termines, tu chromecast se conectará automáticamente a tu punto de acceso cada vez que se encienda para acceder a internet. Cuando termine este proceso de configuración tendrás acceso al chromecast desde TODO aquello que tengas conectado al router en tu casa.
 
IMPORTANTE: solo funciona en red local, por lo que si estás usando los datos del móvil y no lo tienes conectado al router no podrá encontrar el dispositivo.
 
¿Y ahora qué?

Ahora toca usarlo. Mi recomendación es que para ver cómo funciona pruebes primero con YouTube. Es la aplicación por excelencia para este aparatito. No es nada complicado: abres youtube, eliges el vídeo que quieres ver en tu televisión y buscar arriba a la derecha este logotipo:


Y te saldrá un cuadro de diálogo en el que puedes elegir a qué dispositivo enviarlo. Si solo tienes un chromecast parecerá un poco inútil, pero cuando tienes varios te recomiendo que les des nombres identificativos desde la aplicación de Google Home. Así, puedes enviar diferentes contenidos a diferentes chromecasts desde el mismo móvil.

Además, pueden enviar al mismo aparato varias personas. Por ejemplo: yo mando un vídeo de youtube y mientras se está viendo en la tele mi madre encuentra uno que nos quiere enseñar. Lo añade a la cola de reproducción y se van a ir reproduciendo ordenadamente. Simple, pero funcional, ¿verdad?
 
Bueno, después de trastear un poquito con youtube ya has conocido el famoso botón para compartir con chromecast, ¿verdad? Pues es muy fácil: toda aplicación que tenga ese botón te va a permitir “Chromecastear” sin ningún problema.

Aplicaciones para sacarle partido:

Hay muchísimas y no puedo ponerlas todas, pero haré una pequeña recopilación de las más famosas y más molonas para mí.
 
Ver contenido de canales con chromecast: la app de RTVE, Atresmedia, RedBullTV y muchos canales más tienen app que permite enviar contenido a chromecast. Se acabó tener que ir a por el portátil y conectarlo con un largo HDMI.
 
Netflix: por supuesto que no podía faltar esta aplicación. Si tienes cuenta de Netflix y no tienes una smartTv sería un poco complicado conseguir ver Netflix en el televisor, ¿verdad? Ahora ya no. Abres Netflix en tu Android, eliges el capítulo que quieres ver y pulsas el mismo botón que os enseñe en youtube… ¡y a viciarse se ha dicho! Si eres más de ver series y películas gratis tienes otras opciones que también te permiten chromecastear desde servidores gratuitos como Streamcloud, Powvideo y similares. Una de ellas es la aplicación de la web que más tiempo pasa caída del mundo: Pordede. También tienes otras como PelisDroid y SeriesDroid, aunque estas no puedes instalarlas desde el play store. En fin, cuentas con un sinfín de posibilidades.
 
Autodesk Pixlr: sí, la famosa herramienta para editar fotografías tiene aplicación en Android que te permite usar grandes pantallas gracias al Chromecast.
 
AllCast: ¿Quieres enviar contenido local de tu Smartphone y no sabes cómo? Esta app es la que buscas. Y esto es lo que hace: es un reproductor de contenido que lo envía a chromecast. Así de simple y exactamente igual que Youtube o Netflix, pero con las fotos y vídeos de tu propio dispositivo.
 
Spotify: diría yo que esta app es más para Chromecast Audio, pero esque tener un chromecast que solo permite reproducir audio no termina de convencerme. Muchos de nosotros tenemos nuestra TV con un buen home cinema y en los sábados de limpieza nos gusta poner musicote, ¿verdad? Ahora es superfacil: seleccionas las canciones o listas de tu spotify como si fueras a escucharlas en el móvil pero… se reproduce en la tele. Si la tienes con el home cinema conectado lo vas a petar y puedes seguir trasteando todo lo que quieras. Tienes un mundo completamente abierto.
 
Just Dance Now: si, ahora no hace falta tener la Wii para jugar con tu cuñada en nochevieja al justdance, si es que quieres bailar algo con ella. Simplemente bajaros la app y tenedla en la mando durante el baile y que uno de ellos conecte a chromecast: la diversión está asegurada. Aplicación oficial de Ubisoft en el playstore.
 
Educakids: para los más pequeños. Esta compañía proporciona un sinfín de juegos infantiles que además permiten jugarse en multijugador con varios dispositivos. Otras como Castpad convierten nuestra TV en una enorme pizarra para dibujar.
 
Y hasta aquí es suficiente. Has aprendido cómo conectar tu chromecast, como usarlo y cómo sacarle partido. Espero que te haya servido de ayuda. Nos vemos en otro artículo y, hasta entonces, sed buenos (si se puede).

jueves, 24 de noviembre de 2016

Primeros pasos para comenzar con tu impresora 3d

Como ya sabreis desde que os lo conté la semana pasada, hace más de un par de meses que tengo (POR FIN) una impresora 3D. Sí, dos meses y poco no es mucha experiencia, pero toda la experiencia que tengo en el CNC ha hecho que aprenda a pasos de gigante. Os voy a dejar un poquito de lo que he aprendido para que vosotros tambíen aprendais algo más hoy.


1) No solo es la impresora 3d

Cuando fabricas piezas de cualquier material es muy raro que el acabado de máquina sea perfecto. Ya puedes tener una impresora 3d como yo de 100 euros o una Matsuura de 3 millones de euros que te va a tocar tener algo de herramientas para dar el último paso de fabricación: el apartado manual. Además de que tendrás que verificar medidas, hacer mantenimiento a la máquina y, en fin, todo lo que implica un proceso productivo. Por tanto, si bien es cierto que el mayor desenvolso es, sin duda, la impresora 3d, tendrás que gastarte un poquito más en herramientas.

Calibre: esencial para medir a la hora de diseñar una pieza y para verificar la medida al finalizar. Existen analógicos y digitales (estos últimos más precisos). Ambos son igual de exactos, pero el digital te muestra los decimales con exactitud, más de lo que tu vista alcanza a diferenciar en un analógico. La desventaja es que el digital lleva pilas y el analógico no. Teniendo en cuenta que las resoluciones con las que trabajaremos habitualmente rondarán los 0.2mm el calibre analógico es más que suficiente.

PRECIO: 16 euros en una ferretería común.

Nivel de burbuja: no lo veo tan esencial como el calibre, pero viene muy bien por 5 eurillos. Importante a la hora de nivelar correctamente la cama caliente y el eje X. Las primeras calibraciones antes de tener el nivel de burbujas las hice sin disponer de uno y la impresora funcionaba perfectamente, puedes omitir esta compra. Ojo: si es demasiado grande no podrás calibrar el eje X, cómpralo más bien pequeño.

PRECIO: 5 euros en bricor.
Cinta de carrocero: preferiblemente ancha. Es para proteger la cama caliente de las rayaduras al hacer palanca con la paleta y despegar la pieza. No es obligatorio, pero muy recomendable. Además, el plástico se pega muchísimo más a la cinta que a la propia cama desnuda, por lo que evita dobleces inesperadas o que se suelte. Mucho más barato que la laca, y dura mucho.

PRECIO: 4 euros en bricor.
Otras herramientas manuales: tales como una cuchilla de modelismo, una rasqueta, rebarbador, una paleta, papel de lija y todo lo que se os pueda ocurrir para ayudaros al terminar la pieza. Recomiendo también un juego de brocas, aunque sean malas, para repasar el interior de los agujeros, que siempre suelen quedar hilillos al rezumar el extrusor. El rebarbador y las cuchillas son algo caras, yo ya las tenia por casa. Unos 25 euros contando con todo.

Organizador de escritorio: si quieres dar un paso más (como yo) en el frikismo y tener tu mini taller, te recomiendo que te hagas uno como el que yo mismo me diseñé en las fotos:



Tiene huecos a medida para el calibre (el estuche negro rectangular), el nivel de burbuja, la regla, la cinta de carrocero, hueco para 2 paletas, para los alicates. Tambíen tiene un hueco como veis para cables: tengo el ordenador un poco lejos de la impresora y para conectarla uso un alargador de usb macho-hembra de 3 metros, y ahí se guarda. Incluye un cilindro para las cuchillas, destornilladores, tijeras y lo que necesiteis. Además, cuenta con un cajón grande, uno mediano, dos pequeños y otros dos pequeños con divisiones para poder guardar de todo: tornillos, arandelas, tuercas, piezas impresas, varillas, alguna llave inglesa y, en fin, todo lo que necesites. Pensad cuánto costaría un organizador de escritorio con toda esa capaidad si lo compras en una librería. Y además, al crearlo tú lo haces a tu medida. Lo único es que te va a llevar unas 40 horas de impresión (mucha paciencia, son varias piezas) con lo que conlleva del considerable gasto de PLA y de energía, pero aún así no pasa de los 7 euros según he calculado.

2) Ya tengo todo. ¿Y ahora?

Si todavía no quieres o no tienes tiempo para diseñar tus propias piezas puedes buscarlas en repositorios como thingiverse.com. Te descargas el cad y solo tienes que laminarlo, que es el punto siguiente.

3) Gcode: el hijo de ISO CNC

Gcode es el código de instrucciones que entiende tu impresora. Supongamos que te descargas una pieza del repositorio mencionado antes. Ese archivo con extensión .stl no lo entiende tu impresora. Tienes que pasar ese archivo por un proceso que se llama laminación. Yo utilizo el software Slic3r. Este programa debes configurarlo para tu impresora y genera todos los movimientos que va a tener que realizar, así como el ajuste de temperaturas, etc. Una vez obtenido el archivo de extensión .gcode ya podrás imprimirlo.

4) ¿Cuánto tiempo va a llevar? ¿Cuánto plástico voy a consumir?

La paciencia es imprescindible en este proceso. No es raro que una pieza tarde más de 5 o 6 horas en terminar. Yo estoy acostumbrado a poner la máquina a trabajar por las mañanas a las 7 cuando me levanto, así vuelvo del trabajo y sigue trabajando, y si es muy larga aprovecho todo el día para no tenerla por la noche encendida haciendo ruido. No obstante, supongamos que a las 5 de la tarde quiero hacer una pieza. Es esencial que no tarde más de 8 horas, porque ya terminaría sobre la una. Existe un software de código abierto que se llama Gcode Viewer. Lo que hago siempre tras crear el archivo de gcode con Slic3r es pasarlo por esta herramienta, que me dice cuánto va a tardar, cuántos metros y gramos de plástico voy a gastar y hace estimaciones incluso con la electricidad consumida. Te permite ver capa por capa todos los movimientos de la máquina y analizar muchas más cosas. Es bastante preciso a la hora de calcular el tiempo, pero no siempre acierta. Normalmente indica menos de lo que realmente es. Lo que hago es multiplicar el valor que me da por 1.5 para prevenir exageradamente cuánto va a tardar.

5) ¿Micro sd o conectada al ordenador?

En cuanto a calidad de impresión y rapidez de arranque es mejor manejarla desde el ordenador. Utilizo el software Repetier. Permite además mandar códigos y controlar manualmente la máquina.

Ventajas de tabajar desde el ordenador: no hace falta andar metiendo y sacando la tarjeta y se alcanza mayor precisión que desde la micro sd.

Desventajas: el ordenador va pasando orden por orden a la máquina. Existe el riesgo de que ocurra lo que se conoce como infarto del driver: se produce un error en la comunicación impresora - pc y la impresión se deteiene. Normalmente, toca tirar lo que ya se ha hecho y reiniciar. Por tanto, para piezas largas, siempre usa la micro sd. Es un poco engorroso: tienes que desmontarla y quitarla, meterla al pc, copiar los archivos con un nombre que sepas identificar, volver a meterla y montarla e imprimir. Pero, además, no tienes el ordenador encendido durante todo el proceso. 

Como consejos principales creo que teneis más que suficiente para saber qué concierne todo este mundillo de la impresión 3d. Poco a poco iré creando más tutoriales concretos y consejos de cada paso. Nos vemos el jueves que viene. No olvidéis ser buenos si se puede.

jueves, 15 de septiembre de 2016

Comandos básicos para manejar archivos en Linux

Bienvenidos de nuevo a un tutorial del frenético informático. Hoy vuelvo con Linux (¡Cómo lo echaba de menos!). Voy a hacer una serie de artículos para principiantes en linux, y es que a veces nos olvidamos de que hay gente que sabe menos que nosotros, y un poquito de ayuda siempre viene bien. Hoy voy a centrarme en los archivos. Habitualmente en Linux tenemos que recurrir a la consola de comandos (más conocida como Bash) para ejecutar algún tipo de archivo especial como sh o desempaquetar un tar.

Pues bien, he recopilado en una lista los comandos que considero más importantes para el manejo de ficheros en un sistema Linux.

Moverse por los directorios

No puedo empezar este tutorial sin antes enseñaros cómo se desplaza un usuario por los archivos de un sistema Unix mediante los comandos. Para ello, requerimos solamente un comando: cd. Este comando se encarga de desplazarnos al directorio que le indiquemos por parámetro. Por ejemplo, el siguiente comando nos desplazará al escritorio:
 
cd /root/Escritorio

Root hace alusión a la carpeta de usuario, que coincide con el nombre de usuario, que en mi caso es root. Si es tu caso te llamas manolo, pues manolo tendrás que poner.

Para volver a ir a la carpeta inmediatamente superior a la que estamos solamente necesitamos escribir cd ..

El punto individual significa partir desde el directorio actual (para rutas relativas). El comando cd ./carpetaEjemplo significa que queremos que nos lleve a la carpeta llamada  "carpetaEjemplo" que está dentro de la carpeta en la que nos encontramos.


Rutas absolutas vs. rutas relativas

No existe una única forma de llegar a un directorio en un sistema, normalmente siempre existen 2. Nos referimos a la ruta absoluta cuando hablamos de la ruta completa que ha de seguirse para llegar a un directorio determinado. El comando que he puesto antes de ejemplo es la ruta absoluta de mi escritorio. Es posible llegar a una carpeta desde otra. Es decir, por ejemplo, si nos encontramos en la carpeta Imágenes, el comando para acceder al escritorio (en mi caso) sería el siguiente, lo explico después:

cd ./../Escritorio

Escribimos primero cd ./ para indicar que partimos desde la carpeta en la que nos encontramos (Imágenes) y que es, por lo tanto, una ruta relativa. Después los dos puntos .. significan, como hemos visto antes, que retrocedemos una carpeta, por lo que ahora nos encontramos en nuestra carpeta home. Después, le decimos que vaya a escritorio porque es en la carpeta home donde se encuentra el escritorio. ¿Me he explicado bien? Espero que sí.

Mostrar archivos

Para mostrar archivos en linux tenemos el comando LS. Este comando muestra, por defecto, todos los archivos y subcarpetas de un directorio sin incluir los ocultos, como vemos en la siguiente imagen:

No obstante, podemos modificar el comando añadiendo flags según necesitemos. Algunos ejemplos son:

ls -a -> muestra todos los archivos incluyendo los ocultos
ls -f -> muestra todos los archivos junto con el tipo de archivo
ls -lac -> muestra todos los archivos, incluyendo los ocultos, con detalles y en columnas.

Borrar archivos

El comando para borrar archivos es RM. Nos situamos en el directorio y escribimos "rm archivo" y ese archivo será eliminado. Cuidado con no confundirte de archivo, este comando no pide confirmación.

Podemos borrar un archivo sin estar situados en su directorio nativo, para ello solo tenemos que escribir el directorio absoluto o relativo en lugar del nombre. Es importante recordar que, normalmente, cuando hacemos referencia al nombre del archivo nos referimos al archivo.extensión. Muchos comandos de este tipo no funcionan si no se indica el nombre completo incluyendo la extensión de archivo.

En caso de que queramos borrar una carpeta con todos sus archivos y subdirectorios tendremos que añadir el flag -rf, como indica el siguiente ejemplo:

rm -rf carpeta

Copiar/mover

Muy simple. Para copiar el comando es CP y para mover es MV. Eso sí, debemos respetar el orden. Primero ponemos el archivo que queremos copiar / mover y, después, el directorio absoluto donde queremos ubicar la copia.

cp archivo /root/Escritorio
mv archivo /root/Escritorio

Otros

Además de los que os he mencionado también son muy útiles los siguientes comandos:

mkdir para crear carpetas
cat para mostrar archivos
man para pedir el manual de alguna palabra clave
head para leer la primera parte de un archivo. Si no indicamos nada mostrará automáticamente las 10 primeras líneas. Si escribimos head -x nos mostrará X líneas según el valor que le demos a la variable.
tail igual que head, pero esta vez nos mostrará las 10 últimas líneas o las que le indiquemos.

lunes, 20 de junio de 2016

Mecánico, sólido o híbrido: tres formas distintas de gestionar tu almacenamiento


Discos duros sólidos, mecánicos e híbridos. ¿Cuál de ellos para mí?
Si quieres mejorar el almacenamiento de tu pc o simplemente quieres comprarte uno nuevo, oirás estas tres palabras. Pero, ¿conoces qué implica cada una de ellas?


Los mecánicos tradicionales



Un conjunto de discos (también llamados pletinas) que giran gracias a un duradero motor entre cabezales que se encargan de realizar las tareas de lectura/escritura. Estos discos ofrecen gran capacidad de almacenamiento a un precio muy barato y pueden alcanzar velocidades de lectura / escritura de unos 100 MB/s.

No están nada mal, sobre todo teniendo en cuenta que por apenas 50 euros puedes tener más de mil gigabytes de almacenamiento. No obstante, al llevar tantos componentes mecánicos y giratorios, son poco resistentes a golpes y su velocidad de transferencia es relativamente lenta. Han sido el estándar hasta ahora que los SSD empiezan a dominar el mercado.

Discos sólidos o SSD


SSD significa “Solid State Drive” y son los famosos discos rápidos de los que siempre oímos hablar. ¿Ventajas? Velocidad de lectura y escritura muchísimo más rápida que cualquier mecánico. Además, son mucho más seguros al carecer de piezas móviles, ya que soportan muy bien los golpes e incluso generan menos calor que los tradicionales. En fin, el hecho de carecer de piezas móviles mecánicas reduce calor, reduce desgaste y consumo, aumenta eficiencia y mejora la resistencia a golpes. Son mucho más ligeros y pequeños que los convencionales, y son cien por cien silenciosos. En definitiva, han sido un gran paso para el mundo de la tecnología.

Y todavía no estamos aprovechando del todo esta tecnología. Actualmente, los puertos SATA 3 soportan hasta 6Bg/s. OJO: 6Gb NO es 6GB. Estamos hablando de 6 GIGABITS y no de 6 gigabytes, por lo que la velocidad real que mostrará en nuestro PC debemos dividirla entre 8: un total de unos 600-700 MB (MegaBytes) por segundo. Por eso existen nuevas tecnologías como el NVME o los discos sólidos por PCIe, como si de una gráfica se tratase. También existen los disco sólidos M.2, que alcanzan velocidades de hasta 32 Gb por segundo (4GB reales).

Pero ojo que no todo en este mundo es perfecto. Los discos sólidos, si bien no sufren desgaste mecánico, sí que sufren de desgaste electrónico. La velocidad de escritura y lectura se irá reduciendo de manera directamente proporcional a la cantidad de GigaBytes  que hayas leído o escrito. Por cada bit escrito o borrado el disco va a sufrir un desgaste y, con el tiempo, puedes ver que la velocidad de tu SSD ha bajado de los 550MB originales por segundo hasta, por ejemplo, los 300 o incluso menos. Por esta razón el tiempo de vida de los SSD de más capacidad es mayor. No es lo mismo haber escrito un total de 1000 GB en un SSD de 100 gb (que hemos escrito diez veces cada celdita) que los mismos 1000 GB de escritura en un SSD de 1000 GB, en el que solo hemos escrito una vez por cada celda. ¿Es esto un problema por el que preocuparse? Desde luego que no. Empezarás a notar la bajada de rendimiento después de miles de horas de uso intensivo, no es algo que pase al primer año de uso.

Ni negro ni blanco: discos híbridos



Los coches híbridos tienen un motor gasolina y otro eléctrico, y los combinan para obtener lo mejor en eficiencia y rendimiento. Pues un disco híbrido es exactamente lo mismo: un disco duro con un porrón de GB mecánicos y unos pocos sólidos. Por ejemplo, 8 sólidos y 500 mecánicos. De esta forma, puedes instalar el kernel del SO en la parte sólida y conseguir un arranque más optimizado, incluso puede que te sobre espacio para instalar dos o tres programitas ligeros que uses a menudo (Word, navegador, cliente de correo…) y todo lo demás en la parte mecánica. ¿Ventajas? Pues que es más barato que comprarte, por ejemplo, mil GB sólidos y aprovechas las ventajas de velocidad de los SSD y de gran capacidad de los mecánicos, pero al igual que tienes las ventajas de ambos, también tienes las desventajas de ambos.

Lo que menos me gusta de este inventito es el precio. Por unos 90 euretes puedes comprarte un disco de 1Tb mecánico y solo 8 gb sólidos… pero esque si pagas 40 euros por un sólido de 120GB con otros 50 euros de un mecánico de 1TB tienes, por el mismo precio o incluso menos, una cantidad muchísimo mayor de disco sólido. ¿Desventaja? Que si cuentas solo con espacio para un disco, te va a tocar esta opción. Normalmente, en los portátiles puede ponerse una bahía adaptadora renunciando al lector de cds (que ya casi está en desuso) y puedes contar entonces con tu SSD completo junto al espacio de tu mecánico si realmente necesitas toda esa capacidad de almacenamiento. Si quieres saber cómo, visita este tutorial en el que te lo explico detalladamente.

Otra cosa es que, por ejemplo, quieras instalar un disco sólido a tu consola. En ese caso es imposible añadir dos discos, y si quieres mil gigabytes sólidos… te vas a dejar más dinero en el disco sólido que en la consola. Yo creo que a una consola es ridículo ponerle un SSD, pero si lo quieres, creo que es entonces el caso en el que necesitas un disco híbrido.

Conclusión:

Seré conciso: una buena combinación de disco sólido + disco mecánico es lo más barato y ofrece una capacidad suficiente de almacenaje sólido junto a todo el montón de espacio que necesites en mecánico sin reducir la velocidad de tu sistema.

En portátiles te recomiendo gastarte el dinero en un disco de 250 gb, no es caro y tienes suficiente para bastante. Si es vital para ti tener 1TB, entonces puedes tirar de bahías adaptadoras, como la que te enseño en el artículo citado. Pero lo que no recomiendo, desde luego, es tirar el dinero en un disco híbrido ya que vas a tener muy pocos GB sólidos y te va a salir igual de caro. Y tú, ¿por qué opción te decantas?