Dormir la pantalla programáticamente

Hace varios años, no recuerdo bien dónde, encontré el código para enviar mensajes a la pantalla desde un programa .NET. Con un poco de lectura de la documentación (y acá), escribí un programa en C# para hacer sólo una cosa: apagar la pantalla de mi computador portátil.

Soy consciente de que esta probalemente no es la manera más elegante de lograr eso, pero desde que lo desarrollé (cosa que no recuerdo me haya tardado más de 5 minutos), puse un acceso directo en mi barra de tareas y es de las cosas más útiles que tengo allí. Cada vez que deseo dejar el portátil prendido pero no deseo esperar a que se apague la pantalla, pulso en el ícono o la combinación de teclas y la pantalla se apaga. A continuación pongo a disposición el código a manera de curiosidad.

using System.Runtime.InteropServices;

namespace TurnOffDisplay
{
    class Program
    {
        static public int WM_SYSCOMMAND = 0x0112;
        static public int SC_MONITORPOWER = 0xF170;
        [DllImport("user32.dll")]
        private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);

        static void Main(string[] args)
        {
            SendMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER, 2);

        }
    }
}

Para reproducir, crear un proyecto en Visual Studio (puede ser Express) con un único archivo y pegar el código.

Sesiones en Zend Framework 2

Para usar sesiones en Zend Framework 2 podríamos usar la funcionalidad nativa de PHP para manejar sesiones, pero rápidamente nos vamos a encontrar con que conforme la complejidad de la aplicación crece, se nos va a salir de las manos el manejo de todos los datos concernientes a las sesiones de nuestros usuarios. Es ahí donde entra en juego el componente Zend\Session, que hace parte de Zend Framework 2. En esta entrada explicaré cómo usar Zend\Session para iniciar, guardar y consultar información de una sesión. Debo notar que lo expuesto acá solo representa el uso más básico de Zend\Session, e información más completa acerca de todas las posibilidades ofrecidas se encuentra en la documentación oficial, así como en diferentes lugares en la red. Para empezar, sin embargo, considero que lo expuesto en esta entrata consiste en un buen punto de partida.

Para este ejemplo no usaré la aplicación esqueleto de Zend, sino sólamente los módulos necesarios para el manejo de sesiones. Usando composer, mi archivo composer.json es el siguiente:

{
	"require": {
		"zendframework/zend-session" : "2.3.*@dev",
		"zendframework/zend-eventmanager": "2.3.*@dev"
	}
}

Después de ejecutar php composer.phar install, procedemos a requerir vendor/autoloader.php. Usaré un solo archivo, index.php, para ejemplifcar el uso del componente. Primero, añadimos los siguientes usos:

<?php
require "vendor/autoload.php";

use Zend\Session\Config\SessionConfig;
use Zend\Session\Container;
use Zend\Session\SessionManager;

SessionConfig maneja los diferentes parámetros de configuración de la sesión, SessionManager maneja acciones de manejo de sesión como Inicio, Destruís, etc., y Container es la interfaz priparia para el manejo de los datos de sesión. Ahora iniciamos el SessionManager con las opciones deseadas:

$sessionConfig = new SessionConfig();
$sessionConfig->setOptions(array(
	'remember_me_seconds' => 180,
	'use_cookies' => true,
	'cookie_httponly' => true
	));
$sessionManager = new SessionManager();
$sessionManager->start();
Container::setDefaultManager($sessionManager);

Container::setDefaultManager($sessionManager) lo usamos en caso de que estemos usando varios SessionManager, o prefiramos ser explícitos. A continuación vamos a mostrar al usuario la página en caso de que no se encuentre logeado. Hay que tener que en cuenta que una cosa es la sesión, y otra cosa es el login. La sesión siempre la iniciamos, y la información sobre si un usuario se encuentra autenticado en el sistema es información que se encuentra en la sesión. Se puede pensar en la sesión como una sesión de navegación. Es decir, usuarios del sitio que no estén autenticados también tendrán una sesión, sólo que ésta no estará asociada a un usuario en particular.

if(!isset($_REQUEST['action'])){
	$session = new Container('userdata');
	if($session && $session->username){
		echo "Username: " . $session->username;
		?>
		<a href="index.php?action=logoff">Salir</a>
		<?php
	}
	else{
		?>
		<form action="index.php">
			<label for='username'>Username</label>
			<input type="text" name="username" id="username" />
			<input type="submit" value="login" name="action" />
		</form>
		<br/>
		<?php
	}
}

Para verificar que se trata de la página principal, verificamos que la acción no exista, y que el nombre de usuario (atributo username) no esté iniciado. Para acceder a los datos de la sesión es necesario iniciar el contenedor, $session = new Container('userdata'). Los contenedores son usados para dividir los datos, siendo en este caso username el nombre de estos datos. Más contenedores pueden ser creados, con otros nombres y para otros datos.

Si el usuario se encuentra autenticado, vamos a mostrar su nombre y proveer un vínculo para salir. Si no se encuentra autenticado, mostramos un formulario en el que pedimos el nombre; en nuestro caso “autenticarse” se refiere a dar el nombre. Ahora vamos a mirar cómo se realiza la autenticación. De acá lo que nos interesa es cómo se guardan datos en el contenedor:

if($_REQUEST['action'] == 'login'){
	$session = new Container('userdata');
	$session->username = $_REQUEST["username"];
	echo "Sesion iniciada. Username: " . $session->username;	
	echo "<a href='index.php'>Volver</a>";
}

Acá igual, iniciamos el contenedor y guardamos la información del nombre de usuario directamente desde $_REQUEST; también proveemos un vínculo para ir a la página principal. Ahora veamos cómo funcionaría el cierre de sesión:

if($_REQUEST['action'] == 'logoff'){
	$session = new Container('userdata');
	unset($session->username);
	echo "Sesion cerrada.";
	echo "<a href='index.php'>Volver</a>";
}

Simplemente borramos la información del contenedor con unset.

Como podemos ver, el sistema de contenedores que utiliza Zend Framework es muy útil porque nos permite tener la información que necesitemos de manera organizada. Con las opciones de configuración tenemos más control de nuestra sesión, además. En un entorno MVC como el de la aplicación esqueleto de Zend Framework 2, la inicialización del SessionManager podría ir en Module.php, mientras que el acceso y guardado de datos en los contenedores iría en acciones de los controladores.

Mostrar ventanas de Linux en Windows usando X

Uno de los aspectos más interesantes y con menos frecuencia mirados de X, es su naturaleza cliente-servidor. Desde sus inicios, X fue diseñado de manera que pudiera sacar todo el provecho posible de la red. Esto nos permite realizar cosas muy interesantes, como trabajar en varios computadores al tiempo desde una sola máquina o enviar ventanas a otros computadores. Precisamente eso último es lo que voy a describir en esta entrada.

En mi escritorio cuento con dos máquinas en las que normalmente trabajo:

  • Un escritorio (viejo portátil convertido) con Ubuntu 12.04.
  • Un portátil con el Windows 7 con el que venía.

Me gusta más trabajar en el escritorio cuando se trata de temas de programación, puesto que me parece que Linux es un ambiente más amigable para estos menesteres. Sin embargo, por temas de compatibilidad de aplicaciones y hardware, también suelo estar un buen tiempo en el portátil. Dado que mi computador con Windows solo cuenta con 4 GB de memoria RAM y que Windows no es tan bueno manejando memoria cono Linux, muchas veces tengo que mover la silla y cambiar de máquina varias veces en unos minutos.

Acepto que este puede no ser el mejor motivador para configurar lo que describiré en esta entrada, pero el hecho de que se puede hacer y es interesante también es un motivo válido.

Para este tutorial vamos a mostrar una ventana de Lunix en el escritorio de Windows, por medio el protocolo X. Para esto vamos a:

  1. Instalar X y SSH en Windows por medio de Cygwin
  2. Configurar SSH en Linux (asumo que SSHD ya está instalado)
  3. Conectar los dos computadores

Es mejor que los computadores involucrados estén conectados a la red por medio de cable, para mejorar el rendimiento.

Instalación de Cygwin

Cygwin es un proyecto que pretende dar a usuarios de Windows un entorno similar a Unix para aplicaciones nativas a Windows y para desarrollo. Dentro de las aplcaciones proveídas por Cygwin están el cliente SSH y el servidor X requeridos para lo que vamos a hacer. Para instalar Cygwin vamos a ir a la página del proyecto y seguir las instrucciones, según queramos la versión de 32 o 64 bits. Los paquetes que vamos a instalar son los siguientes:

  • xorg-server, es el servidor X para correr los programas gráficos.
  • xinit, es requerido para iniciar el servidor X.
  • openssh, para realizar conesiones seguras a los programas cliente (en mi caso la máquina con Ubuntu).

cygwin-openssh-install-scp-ssh[1]

Podemos usar la barra de búsqueda para buscar los paquetes. Una vez instalado el entorno en la máquina Windows, vamos a proseguir con el siguiente paso.

Configurar SSH en Linux

Para este punto voy a asumir que el servidor de ssh ya se encuentra instalado en la máquina con Linux. Si no es así, en Ubuntu esto es fácil de hacer con apt-get install openssh. Vamos a configurar ssh para poder conectarnos seguramente de un equipo al otro.

Abrimos el archivo /etc/ssh/sshd_config con algún editor de texto, y nos aseguramos que la siguiente opción está activa (no está comentada y existe):

X11Forwarding yes

Esto habilitará la conexión segura entre el computador que tiene el programa y el que tiene el servidor X. De otra manera tendríamos que abrir el servidor X con la opción -ac, lo que deshabilita la autenticación y puede abrir nuestro equipo a ataques de seguridad.

Conectar las máquinas para usar la funcionalidad

Ahora que todo está configurado, vamos a iniciar un programa cliente en el computador con Linux, y usarlo en el computador con Windows. Primero, iniciamos el servidor X en Windows. Abrimos la terminal de Cygwin y introducimos el siguiente comando:

X -multiwindow &

Esto inicia el servidor X con la opción multiwindow, que significa que por cada ventana que el cliente cree en el computador con Linux, se va a crear una ventana de Windows. El parámetro &amp; nos devolverá el control una vez termine de iniciar el servidor, para poder seguir introduciendo comandos. Ahora vamos a iniciar la variable DISPLAY para que el reenvío por SSH funcione:

export DISPLAY=:0

Con esto podemos conectarnos al computador donde residen nuestros programas:

ssh -Y usuario@servidor

Nos pedirá la contraseña y una vez adentro, ya podemos iniciar la aplicación que queramos, la cual aparecerá en nuestro escritorio de Windows como una ventana mas, por ejemplo:

gnome-system-monitor

Una ventana más


Existe otra herramienta para realizar este proceso más fácilmente llamada xming, que provee un servidor X para Windows listo para ser usado. Sin embargo en mis pruebas el funcionamiento en general de Cygwin X fue muy superior, de modo que considero que el esfuerzo vale la pena.

Por supuesto, también es posible realizar el mismo proceso al revés. En esta caso la limitante está en que sólo los programas gráficos proveídos por Cygwin serán visibles en el escritorio de Linux usando este método. Es decir, tener Visual Studio, por ejemplo, funcionando en el escritorio de Linux no sería posible. Para lograr esto considero que lo más sensato es usar una aplicación de escritorio remoto como TeamViewer, o virtualizar un entorno Windows. Hay soluciones más óptimas pero requieren mucho más trabajo.

Tres enfoques para manejar AJAX

En esta entrada comentaré tres métodos de manejar Ajax. Para efectos de la entrada usaré PHP y jQuery, ya que son tecnologías que conozco y que me permiten codificar los ejemplos de manera compacta y rápida, pero otras tecnologías del lado del servidor y del cliente puede ser usada. La idea de la entrada es ejemplificar los conceptos usados.

AJAX es una manera de enviar solicitudes al servidor y actualizar la página con la información obtenida sin realizar una recarga completa. La idea es minimizar el tráfico de red usado, al evitar cargar cosas que ya hemos cargado como imágenes o cabeceras, al tiempo que agilizando la experiencia del usuario con nuestra aplicación. En la entrada usaré jQuery, que es una librería de JavaScript muy popular para, entre otras, ayudarnos con este tipo de tareas.

Por ejemplo, digamos que tenemos un formulario de un campo en el que escribimos un número de identificación, y un espacio de respuesta en el que debe aparecer el nombre de la persona que estamos buscando, así:

<!DOCTYPE html>
<html>
<head>
    <title>Consulta de usuario</title>
</head>
</html>
<body>
<h1>Consultar usuarios</h1>
<form id="form_consulta">
        <label for="documento">Documento: </label>
        <input type="text" id="documento" name="documento" />
<div id="respuesta"></div>
</form>
</body>
</html>

Guardamos el código en un archivo PHP, consulta.php. Tenemos así un formulario con id form_consulta, que tiene un único campo, documento, y un div con id respuesta.
Vamos a empezar realizando el proceso sin usar AJAX. Para esto, cambiamos el archivo para que contenga lo siguiente:

<?php
$usuarios = array(
	'123' => 'Pepe Pelotas',
	'535' => 'Juana Juliana',
	'903' => 'Pancho Pecas'
	);
?>
<!DOCTYPE html>
<html>
<head>
	<title>Consulta de usuario</title>
</head>
</html>
<body>
<h1>Consultar usuarios</h1>
<form id="form_consulta" action="handler.php" method="post">
		<label for="documento">Documento: </label>
		<input type="text" id="documento" name="documento" value="<?php echo isset($_POST['documento'])?$_POST['documento']:'';?>" />
		<input type="submit" value="Consultar"></input>
	</form>
<div id="respuesta">
		<?php
		if($_SERVER['REQUEST_METHOD'] == 'POST'){

			if(in_array($_POST['documento'], array_keys($usuarios))){
				echo "Usuario: " . $usuarios[$_POST['documento']];
			}
			else{
				echo "Usuario no encontrado!";
			}
		}
		?></div>
</body>
</html>

El arreglo $usuarios en este caso contiene la información que quedemos obtener. Normalmente este arreglo sería reemplazado por una base de datos, por ejemplo. El siguiente cambio que vemos es en el elemento input con id documento. Ahora vamos a poner en ese campo lo que sea que el usuario escribió en la solicitud anterior, o nada.

Dentro del div de respuesta viene la lógica del servidor que se va a encargar de realizar la consulta y escribirla en el documento. Sólo ejecutamos el código cuando se trata de una solicitud POST, y básicamente pintamos directamente lo que encontremos según la información proveída en la solicitud.

Por supuesto, el problema acá es que estamos recargando totalmente la página cada vez que hacemos una consulta. Estamos descargando la página completa cada vez que realizamos una consulta, y en esa descarga estamos volviendo a transmitir información que ya teníamos, como el título de la página. Eso es lo que queremos evitar.

Primer enfoque: carga parcial de HTML

En este primer enfoque la idea es cargar parcialmente un trozo de código HTML desde el servidor y reemplazar algún trozo definido de nuestro documento con el HTML cargado. Vamos a devolver únicamente el div con la información requerida, y con eso reemplazaremos el div que pusimos. Nuestro archivo quedará así:

<?php
$usuarios = array(
	'123' => 'Pepe Pelotas',
	'535' => 'Juana Juliana',
	'903' => 'Pancho Pecas'
	);
if($_SERVER['REQUEST_METHOD'] == 'GET'){
	?>
	<!DOCTYPE html>
	<html>
	<head>
		<title>Consulta de usuario</title>
		<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
	</head>
	</html>
	<body>
		<h1>Consultar usuarios</h1>
		<form id="form_consulta" action="handler.php" method="post">
			<label for="documento">Documento: </label>
			<input type="text" id="documento" name="documento" />
			<input type="button" id="enviar" value="Consultar"></input>
		</form>
		<div id="respuesta">
		</div>
		<script type="text/javascript">
			$(function(){
				$("#enviar").click(function(){
					$.ajax({
						type: "POST",
						url: $("#form_consulta").attr("action"),
						data: $("#form_consulta").serialize()
					}).success(function(data){
						$("#respuesta").replaceWith(data)
					}).error(function(){
						alert("error!")
					})
				})
			})
		</script>
	</body>
	</html>
<?php
}
if($_SERVER['REQUEST_METHOD'] == 'POST'){
	if(in_array($_POST['documento'], array_keys($usuarios))){
		echo '<div id="respuesta">';
		echo "Usuario: " . $usuarios[$_POST['documento']];
		echo '</div>';
	}
	else{
		echo '<div id="respuesta">';
		echo "Usuario no encontrado!";
		echo '</div>';
	}
}

Tomemos un vistazo al código. Lo que más salta a la vista es que ahora estamos dividiendo claramente el cógido entre POST y GET. Cuando el método es GET, mostramos la misma página de consulta que veníamos mostrando, más un código en Javascript que miraremos en detalle más adelante. Si el método es POST, por otro lado, sólo mostramos un div, con el resultado del procesamiento en el servidor.

En el código Javascript hacemos uso de jQuery (que previamente cargamos desde Google) para hacer el llamado AJAX a nuestra página con el método POST y los datos del formulario. Una vez tengamos el div retornado, reemplazamos el div en el documento con el que obtuvimos con la función replaceWith.

Este enfoque nos permite reducir considerablemente el tráfico necesario para realizar ua consulta, obteniendo los mismos resultados de manera más rápida y fluida. Sin embargo, es posible reducir aún más el uso de la red, sólo extrayendo del servidor los datos necesarios.

Segundo enfoque: carga de JSON

En el anterior enfoque cargamos desde el servidor únicamente el HTML que necesitamos actualizar, no toda la página. Como ejemplo, la respuesta del servidor en el caso de una consulta con el documento 535, se vería así:

<div id="respuesta">Usuario: Juana Juliana</div>

Sin embargo, el tamaño de la respuesta se puede disminuir aún más. Podemos devolver únicamente los datos que necesitamos, en este caso el nombre del usuario. Elementos concernientes con el HTML no son concernientes al servidor, de modo que vamos a omitirlos en la respuesta. Para tal efecto, devolveremos los datos que nos interesan, junto a un código de error que vamos a utilizar para mostrar la respuesta según el caso. Todo esto irá en formato JSON. Para que la nueva solución funcione, tenemos que modificar el código Javascript y del lado del servidor (PHP).

Javascript:

 
$(function(){
	$("#enviar").click(function(){
		$.ajax({
			dataType: "json",
			type: "POST",
			url: $("#form_consulta").attr("action"),
			data: $("#form_consulta").serialize()
		}).success(function(data){
			data = $.parseJSON(data);
			$("#respuesta").html("");
			switch(data.code){
				case "NF":
				$("#respuesta").html("Usuario no encontrado!");
				break;
				case "OK":
				$("#respuesta").html("Usuario: " + data.response);
				break;
			}
		}).error(function(){
			alert("error!")
		})
	})
})

PHP:

if($_SERVER['REQUEST_METHOD'] == 'POST'){
	$respuesta = array();
	if(in_array($_POST['documento'], array_keys($usuarios))){
		$respuesta['code'] = 'OK';
		$respuesta['response'] = $usuarios[$_POST['documento']];
	}
	else{
		$respuesta['code'] = 'NF';
	}
	echo json_encode(json_encode($respuesta));
}

Si bien en este ejemplo no se ve claramente el ahorro en ancho de banda que se obtiene con este enfoque, con una mayor cantidad de datos el cambio es importante.

Tercer enfoque: HTML Templates

Cuando tenemos una gran cantidad de datos que obtenemos del servidor, podemos usar el enfoque de HTML Templates para aliviar un poco el trabajo de actualizar los datos en la página. La idea en este enfoque es crear una plantilla de la información a mostrar, poniendo marcadores en las posiciones en que los datos del servidor irán. Una manera de lograr esto es creando una etiqueta script con un descriptor de lenguaje que sepamos que el navegador no soporta, y escogiendo un patrón de caracteres fácilmente identificable, para reemplazar posteriormente con los datos provenientes del servidor:

<script id="responseTemplate" type="html/template">
	<div id="respuesta">{{response}}</div>
</script>

Nuevo script:

switch(data.code){
	case "NF":
	$("#respuesta").html("Usuario no encontrado!");
	break;
	case "OK":
	var template = $("#responseTemplate").html()
	for(key in data){
		template = template.replace("{{" + key + "}}", data[key])
	}
	$("#respuesta").replaceWith(template);
	break;
}

Podemos ver que en el bucle for estamos iterando los datos provenientes del servidor, y reemplazándolos en los marcadores que previamente preparamos en la plantilla. Finalmente, ponemos la plantilla ya llena en la página para mostrar.


Estos tres enfoques para el manejo de AJAX en una aplicación web son en general los más aceptados, sin embargo yo sólo conocí el último hasta hace unos pocos meses. Me pareció una solución tan elegante y sencilla que me inspiró a redactar esta entrada. Personalmente, nunca usaría el primer enfoque, por un lado porque el servidor no debería saber nada de etiquetas HTML o clases, y porque el tamaño de la respuesta puede salirse de control rápidamente.

Proxy en Linux

En algunas organizaciones existe una red que requiere de autenticación por proxy para salir a Internet. Normalmente la configuración del proxy de la red es bastante sencilla y gráfica cuando estamos en un computador con Windows o Macintosh, incluso cuando no vamos a hacer otra cosa más que navegar en una máquina con Linux y alguno de los escritorios más populares. Muchas aplicaciones no toman en cuenta la configuración del proxy del sistema operativo y proveen una interfaz propia para estos menesteres. Es el caso de Dropbox o Synaptic, por ejemplo.
Esto se da aún con más frecuencia cuando estamos intentando acceder a Internet desde aplicaciones en modo de texto en Linux. Dado que estas aplicaciones no dependen de un entorno de escritorio, no pueden esperar que instalemos Gnome o KDE (por ejemplo) para configurar el proxy y usar esa configuración. Están, por así decirlo, una capa por debajo.

Configuración básica

Aún más por debajo de las aplicaciones en modo de texto se encuentran las variables de entorno del sistema. Las variables de entorno http_proxy, https_proxy, ftp_proxy, rsync_proxy y no_proxy son usadas por ciertos programas (como wget y lynx) para extraer la configuración del proxy. Tienen la forma protocolo_proxy. Por ejemplo:

export http_proxy=http://10.203.0.1:5187/
export https_proxy = $http_proxy

Automatizando

Alan Pope, según este artículo de ArchLinux en el que me basé, dio con una manera de automatizar la levantada del proxy:

function proxy(){
  echo -n "Usuario:"
  read -e username
  echo -n "Clave:"
  read -es password
  export http_proxy="http://$username:$password@proxyserver:8080/"
  export https_proxy=$http_proxy
  export ftp_proxy=$http_proxy
  export rsync_proxy=$http_proxy
  export no_proxy="localhost,127.0.0.1,localaddress,.localdomain.com"
  echo -e "\Proxy configurado."
}
function proxyoff(){
  unset HTTP_PROXY
  unset http_proxy
  unset HTTPS_PROXY
  unset https_proxy
  unset FTP_PROXY
  unset ftp_proxy
  unset RSYNC_PROXY
  unset rsync_proxy
  echo -e "\nProxy removido."
} 

La idea es añadir esas funciones a nuestro archivo .bashrc. De ese modo, siempre que tengamos que usar el proxy desde la consola, primero llamamos la función proxy:

$ proxy
Usuario:sergio
Clave:
Proxy configurado.
$ wget www.google.com
...
$ proxyoff
Proxy removido.
$

¿Y sudo?

Como para ahora se supondrá, la configuración del proxy no perdura cuando estamos haciendo tareas que involucran sudo, como instalar paquetes por medio de apt. Para esto, accedemos a la configuración de sudo por medio del comanto visudo y añadimos la siguiente línea:

Defaults env_keep += "http_proxy https_proxy ftp_proxy"

Esto mantendrá las variables de entorno dadas del usuario que está llamando a sudo, en este caso, las correspondientes al proxy.

Disclaimer

Esta entrada es básicamente una traducción al español de la documentación de ArchLinux encontrada en el artículo anterioemente mencionado. La escribo para poner la información a disposición de aquellos que puedan leerla, así como a manera de bitácora.
La red de la Universidad Nacional me obligó a usar esta información. Que la red no haya funcionado y al final me haya dado la misma es otro cuento.

Respecto al tamaño oficio a la hora de imprimir desde Microsoft Office

Escribo este post más a manera de recordatorio, ya que la situación se me ha presentado varias veces y siempre que la logro resolver pienso “¡claro, ya me acordé cómo fue que lo hice esa vez!”. Tiene que ver con la impresión de documentos tamaño Oficio.

Tamaño LegalEl problema, como he dicho, siempre es el mismo: el tamaño “Oficio” no es el mismo tamaño “Legal”. El tamaño Legal listado en Word y otros programas de Office tiene unas dimensiones de un poco más de 21 centímetros y medio por un poco más de 35 centímetros y medio, mientras que el tamaño Oficio que se consigue en las papelerías y que es el más usado (de lo que puedo decir) después del tamaño Carta tiene unas dimensiones de un poco más de 21 centímetros y medio por unos 33 centímetros. A lo largo es como una pulgada de más; al esperar la impresora una hoja Legal pero recibir una tamaño Oficio, no va a imprimir todo, perdiendo información hacia los bordes de la hoja.

La solución, por supuesto, es especificar correctamente el tamaño del papel en el documento. El tamaño correcto se puede encontrar (en Office 2010) yendo un poco hacia abajo en la lista de tamaños disponibles, y se llama 8.5×13.

Todo este problema era causado por mi conclusión de que, al ser el tamaño Oficio el segundo más usado para impresiones en Colombia, y al estar el tamaño Legal segundo en la lista de tamaños que provee Office, los tamaños se correspondían. Pero no es así, de modo que escribo esto también en caso de que alguien más tenga mi misma errónea idea y se esté imaginando que su computador está poseído, como escuché a alguien decir esta mañana.

Depuración web remota de PHP con Xdebug

En este post explicaré los pasos que seguí para configurar la depuración remota sobre Internet de una aplicación web en PHP, usando Netbeans. Primero, la configuración de mis máquinas:

  • Por un lado, tengo una o varias máquinas de desarrollo. Estas máquinas por lo general tienen Windows 7, aunque eso no viene al caso. El desarrollo lo hago usando Netbeans 7.
  • Por otro lado, mi servidor de pruebas es una máquina modesta con Linux, Ubuntu. PHP 5.3 y Apache 2.

El desarrollo lo realizo sobre Dropbox (en algún post algún día explicaré mi arreglo de desarrollo PHP), de modo que donde dejo en una máquina, automáticamente puedo retomar en otra, sin necesidad de hacer nada. El hecho es que mi servidor es fijo, está en mi residencia, y muchas veces me llevo el portátil para adelantar trabajo desde donde me encuentre, usando la conexión móvil de mi celular.

De modo que necesitaba una manera de usar la funcionalidad de depurado de Netbeans, para que se justifique en algo los cerca de 400MB en memoria que consume (bromeo, sí se justifica, además estoy acostumbrado al IDE). Configurar Xdebug para un entorno local es relativamente sencillo, y ya lo había hecho en varias ocasiones en máquinas con Windows. De modo que me lancé de lleno a la tarea de configurarlo para depuración remota. Primero sobre red local, luego sobre Internet.

Instalar y activar Xdebug en Linux

La página de soporte de Netbeans provee cierta información sobre cómo configurar Xdebug en Linux para que funcione con el IDE instalado en la misma máquina del servidor, pero hasta ahí llega; es decir, asume que Xdebug ya se encuentra instalado. Tuve que basarme en otro recurso para poder instalarlo. Resumo el procedimiento para Ubuntu:

Primero, hay que asegurarse que el comando pecl está disponible. Simplemente con escribirlo en consola, el sistema tratará de ejecutarlo y, de no encontrarlo, dirá qué paquete hay que instalar para que esté disponible. En el tutorial dice que se trata de php-dev, pero en mi caso el comando estaba en el paquete php-pear. Sudo apt-get bla bla bla.

Ahora viene lo bueno. Una vez está instalada la aplicación que nos provee pecl, tenemos que ejecutar dicho comando para instalar Xdebug:

# pecl install xdebug

Esto descargará, compilará e instalará la extensión de PHP que tanto anhelamos. Al final de mensajes crípticos y un poco abrumadores por parte de la terminal, se nos informará la nueva ruta en la que quedó el archivo xdebug.so recién compilado. Debemos anotar esa ruta, pues la usaremos después.

Ahora tenemos que añadir las correspondientes lineas de configuración al archivo php.ini, para activar la extensión. Para ubicar el archivo php.ini que vamos a modificar tenemos dos opciones:

  • Escribir un script PHP y correrlo en el servidor con el siguiente código: <?php phpinfo() ?>, o
  • en la terminal, php -i | grep php.ini

Una vez ubicado el archivo, lo editamos y añadimos (o descomentamos) la línea que reza más o menos:

zend_extension = /ruta/que/habiamos/anotado/xdebug.so

Eso instalará y activará Xdebug en Linux, previo reinicio del servidor, claro. Para probar podemos correr el script que dan en el tutorial en el cual me basé.

Configurar Xdebug para depuración remota

Como lo que yo quería hacer no era desarrollar en mi servidor y depurar a golpe de comando, sino en otras máquinas y depurar por medio de Netbeans, no vamos a parar acá.

En el archivo php.ini que hemos editado, el tutorial oficial de Netbeans nos dice que pongamos además las siguientes líneas:

xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000

Estas líneas están bien si se quiere usar Netbeans en la misma máquina que tiene el servidor. Eso lo vemos en xdebug.remote_host = 127.0.0.1. Ahí nos está diciendo que el cliente de Xdebug está en 127.0.0.1, es decir en localhost. Lo que vamos a hacer es comentar esa línea, y en vez añadir la siguiente, para que quede todo igual, menos:

; xdebug.remote_host=127.0.0.1
xdebug.remote_connect_back=1

Esta directiva le está diciendo a Xdebug que trate de conectar a todos los clientes que inicien una sesión de depuración. Esto permitirá hacer depuraciones desde equipos remotos cuyas direcciones IP pueden cambiar. Ahora, sólo es cuestión de configurar los puertos.

Puertos

Tenemos que abrir o redirigir externamente el puerto 9000 a nuestro servidor desde Internet, y a nuestro cliente. Si el cliente (Netbeans) está bajo un router o un firewall, debemos redirigir las conexiones entrantes por dicho puerto en TCP hacia nuestra máquina.

Bono: una buena aplicación que me sirvió para redirigir el puerto de mi teléfono Android hacia mi portátil es Port Forwarder.

Sobre los discos de estado sólido

SSD

Hace menos de una semana compré un ultrabook, con unos impresionantes 256 GB en estado sólido. Pruebas iniciales me dieron aliento en velocidades de escritura, y estaba totalmente encantado hasta que hablando con unos compañeros de trabajo sobre memorias alteradas que dicen tener más capacidad de la que realmente tienen, me asusté. Empecé a buscar por Internet y encontré que una manera de mirar si esto se cumple es llenando el disco al máximo y tratando de acceder un archivo previamente guardado.

Resulta que la manera en que estos discos alterados funcionan, aparentemente, es modificando el controladores que le dicen al sistema operativo cuánto espacio queda. En otros lados dice que tiene que ver más bien con la tabla de archivos de los sistemas FAT32. En este último caso mi preocupación no tendría fundamento, pues mi sistema viene con NTFS por defecto. En el primer caso, por otro lado, la teoría que leí seguía diciendo que una vez se llenaba el disco duro a cu capacidad real, seguía escribiendo y sobre-escribiendo sobre lo que ya estaba en el disco. Esto hacía que los primeros archivos escritos en el disco duro quedaran corruptos e inutilizables. En mi mente el miedo a la estafa ya estaba andando, y hice lo que cualquier haría: llenar el disco a su máxima capacidad y tratar de acceder algún archivo previamente guardado.

Mala idea. No sólo comprobé que no había absolutamente nada malo con mi disco, sino que el sistema de archivos quedó completamente fragmentado. Después de comunicar que mis temores estaban despejados, hice lo que me recomendaron, y que yo habría hecho aunque no me lo hubieran recomendado: desfragmenté el disco duro. Peor idea. Después de desfragmentar el disco duro se me ocurrió averiguar por la verdadera utilidad de fragmentar un disco duro de estado sólido. Resulta que no solamente es un proceso innecesario, sino que acorta la vida útil del disco duro.

En un disco duro convencional, los platos del disco se mueven, como un CD, y la cabeza lectora del disco duro lee los datos de la superficie de los discos. Cuando se fragmenta el sistema de archivos, quiere decir que pedazos de datos que deberían ir juntos son mandados a diferentes partes del disco, y cuando la cabeza lectora va a leerlos, tiene que moverse más para recuperar todos los pedazos, que si estuvieran cerca físicamente. Eso se traduce en mayor tiempo leyendo datos del disco duro, en caída de rendimiento del sistema, y en mayor desgaste por parte de la cabeza lectora. En un disco de estado sólido, los datos son recuperados a la misma velocidad sin importar si están cerca o lejos. Es por eso que la fragmentación del sistema de archivos no tiene peso en el rendimiento del disco. Es más, la fragmentación es hecha a propósito. Veamos:

Por el diseño y construcción de los discos de estado sólido, estos vienen con un número finito de veces que se puede escribir en cada sector. Una vez se alcanza dicho número, el disco sólo es utilizable como lectura. Este número es bastante alto, suficiente como para que un usuario normal reemplace el disco por uno que venga con un computador más nuevo antes de reemplazarlo por desgaste. Sin embargo ese límite existe y es importante conocer de su existencia.

Los primeros discos duros de estado sólido tenía un problema de agotamiento de vida útil demasiado pronto, ya que los primeros sectores del disco duro alcanzaban su vida útil demasiado rápido, debido al uso normal. Es por eso que se ideó una manera de alargar la vida útil del disco duro. Los que sucede ahora es que, debido a que a los discos de estado sólido no les importa si un pedazo de un archivo quedó cerca a otro o no, ya que la velocidad de lectura y escritura es la misma, cuando un archivo es eliminado y otro añadido, en vez de sobre-escribir el mismo sector, el sistema operativo envía el nuevo archivo a un pedazo del disco que no se hubiera usado últimamente, reduciendo así el número de escrituras de cada bloque, repartiéndolas por todo el disco.

Al llenar completamente un disco duro con información, como yo hice, los pedazos libres que quedan para que el sistema operativo utilice son menos, y las escrituras tienen menos lugar para repartirse. Eso acorta la vida útil del disco duro. No sólo eso, sino que al desfragmentar el disco duro, el sistema operativo trata de mover (escribir) pedazos que no están juntos, para ponerlos juntos. Esto acorta aún más la vida del disco duro, y no trae beneficio aparente (al menos en el primer caso pude comprobar que nada andaba mal con mi disco). Así es que, nunca desfragmentar un disco duro de estado sólido, y nunca llenarlo al tope para después vaciarlo, a menos que absolutamente necesario.

No he visto por ahora ninguna merma en el rendimiento de mi disco duro, aunque uno nunca sabe.

Ajuste de línea en jqGrid

Si se quiere tener ajuste de línea en los nombres de las columnas en una tabla manejada por jqGrid, sólo basta con añadir las siguientes reglas css:

.ui-jqgrid tr.jqgrow td {
  white-space: normal !important;
}

Estas reglas pueden ser añadidas en el propio documento entre las etiquetas

<style>
.ui-jqgrid tr.jqgrow td {
  white-space: normal !important;
}
</style>

o en un archivo aparte. Pero no es recomendado editar el archivo CSS propio de jqGrid.

Guía extrema de Tuning para Gnome: Cursores del ratón (i)

Es esa cosa fastidiosa que se mueve de un lado a otro de la pantalla, que no se sabe para qué es, y sí que molesta. Esa flechita, como no, también se puede cambiar para que nos moleste de una manera diferente a cada vez.

En el cuadro de Apariencia, al que accedemos por medio de clic derecho en el escritorio, o por medio de SistemaPreferenciasApariencia, tenemos una pestaña llamada Tema. En esa ventana están todas las configuraciones que estén guardadas de los temas que usamos. Los temas se componen de Controles, Colores, Bordes de la ventana, Iconos y, lo que nos interesa hoy, Punteros. De cada uno de ellos hablaré en otros posts de esta serie.

Diálogo de selección de cursor

Podemos personalizar el tema actual, haciendo clic en el botón en el que se lee Personalizar…. ¿Fácil, no? En el cuadro que se nos abre, vemos una pestaña por cada uno de los componentes del tema, yendo en el último lugar el puntero o cursor. En esta pantalla es posible cambiar el cursor entre los que tengamos instalados.

Ahora veamos cómo exactamente se instalan los cursores. Un directorio amplio de cursores (y muchos otros aspectos de la apariencia) disponibles para descarga se puede encontrar en Gnome Look. Es un repositorio inmenso de recursos para cambiar la apariencia de nuestro escritorio Gnome. KDE también tiene su repositorio análogo. Los cursores como tal vienen empaquetados y comprimidos en archivos .tar.gz generalmente. Bajo la sección X11 Mose Themes de Gnome Look vamos a escoger el que nos parezca apropiado, y lo descargamos. Para instalarlo, en vez de hacer clic en Personalizar…, vamos a hacer clic en Instalar…. Buscamos el archivo en donde lo guardamos y lo seleccionamos.

Una vez la instalación es exitosa, nos preguntará si lo aplicamos en ese momento o no. Si no, en todo caso podemos cambiarlo en el diálogo de la ventana Personalizar….

También es posible cambiar el tema del cursor mediante la clave de Gconf /desktop/gnome/peripherals/mouse/cursor_theme. Ahí va una cadena que identifica el tema del cursor. En esa carpeta (/desktop/gnome/peripherals/mouse/) también hay otras configuraciones del ratón y su comportamiento, que se pueden modificar en el diálogo Ratón, accesible desde Sistema → Preferencias → Ratón.

Editor de configuración - mouse
Preferencias del ratón

En el siguiente post ahondaré más en lo que significa un cursor de Gnome (y de X11 en general).