Modificando un pequeño amplificador Kustom Tube 12A

Buscando por internet he encontrado en varios foros de habla inglesa que la gente se dedica a modificar este pequeño amplificador híbrido: el Kustom Tube 12A. De todo lo que he leído, la modificación más sencilla es realizar un par de simples cortes para eliminar del circuito de ganancia 4 diodos encargados de hacer distorsión mediante “clipping“. No me he podido resistir y me he atrevido a hacerlo. La mejora de sonido al activar la sección de ganancia es notoria. Lo mismo me animo a añadirle un conmutador y un led para poder activar o desactivar esta modificación.

IMG_3729 IMG_3730

 

Fabricando una imitación de una guitarra Parker

Hace 4 años (creo) construí un guitarra con la forma de una Parker, reutilizando un mástil  de una guitarra que antes estuvo montada en una imitación de Explorer que también construí y que provenía de una guitarra destrozada abandonada en un piso de estudiantes.Cometí algunos errores pero al menos la terminé y sonaba.

He encontrado en la librería de mi blog estas viejas fotos y he decido recuperarlas para “bien de la humanidad”

Montar un servidor REST (II)

Hace unos meses empecé a explicar cómo montar un servidor REST sencillo para servir datos a una aplicación móvil (o de cualquier otro tipo) de forma rápida y reusable. En esa segunda parte voy por fin a completar la explicación entrando en la parte más interesante del código. Aprovecho para aclarar algo que se me pasó en la anterior entrega: parte de este código y las ideas de cómo estructurar todo el servicio en si provienen de este estupendo artículo.

Nos quedamos por ver la clase que debía procesar la petición. En nuestro proyecto, para cada recurso que necesitemos manejar deberemos crear una clase RecursoController, derivada de la clase RESTcontroller . También será necesario crear una clase RecursoModel, hija de RESTmodel,  que se encargará de la interacción con la base de datos. Pero lo veremos después.

La clase RESTcontroller comienza con las definición de unas pocas propiedades y cuatro métodos  abstractos que deberemos implementar para cada entidad.

abstract class RESTcontroller
{
	protected $classname;
	protected $data;
	public $ID;

	abstract function post(&$error);
	abstract function put(&$error);
	abstract function get(&$error);
	abstract function delete(&$error);

 	.
	.
	.
}

La propiedad $data se utiliza para almacenar los datos recibidos en la petición. $classname se utiliza para que la clase hija indique a RESTController qué tipo de entidad maneja. Se utiliza para crear el objeto JSON o XML adecuadamente. La propiedad pública $ID sirve para identificar el recurso que se está tratando. Cuando se trabaja con una colección de recursos esta propiedad vale NULL.

Los métodos abstratos son los que debemos completar en cada clase derivada para responder a cada unas de las 4 operaciones REST básicas. Deben devolver un array de pares clave-valor (un diccionario hablando con mayor propiedad), cuyas claves son los nombres de las propiedades y los valores los obtenidos en la operación. Si el resultado de la operación es un conjunto de entidades (lo cual ocurre generalmente en las operaciones get en las que no especificamos un ID), estos métodos deben devolver un array de diccionarios como los que he descrito. Si queremos notificar algún error, lo haremos a través del parámetro por referencia $error. Por ahora esto puede resultar demasiado abstracto, pero espero que quede más claro al final de esta entrada.

Como vimos en la anterior entrada, index.php, entrega el control al método processRequest de la clase recursoController:

public function processRequest($request_method, $content_type, $data)
{	
	// Copiamos los parámetros recibidos 
	// para usarlos en la case derivada.
	$this->data = $data;
	// Obtenemos el nombre del recurso
	// a partir de la propiedad o del 
	// nombre de la clase
	$classname = isset($this->classname)?$this->classname:get_class($this);

	// En función del tipo de petición
	// llamamos a un método u otro
	// (definidos en la clase derivada)
	switch($request_method) {		
	case 'get':
		$error = "";
		$result = $this->get($error);
		.	
		.
		.
		break;	
	case 'post':
	case 'put':	
		$error = "";
		if ($request_method == 'post') {
			$result = $this->post($error);
		} else {
			$result = $this->put($error);
		}	
		.
		.
		.
		break;
	case 'delete':
		if($this->delete($error)) {
			.
			.
			.
		}
		break;
	default:
		RESTcontroller::sendError(500, "Unkwon request method", $content_type);
	}
}

El código de arriba está explicado básicamente en sus comentarios. Simplemente en función del método solicitado por el cliente se llama a un método u otro (que debemos implementar en la case derivada). Si os fijáis, utilizo el mismo caso del switch para los métodos putpost, porque como vamos a ver el procesamiento de la respuesta es el mismo. En caso de que el método pedido no sea reconocido, se devuelve un error mediante un método de clase que no tiene mucho misterio, y el poco que tiene será desvelado cuando terminemos con este.

Las clases derivadas de RESTController nos van a devolver los resultados  como diccionarios (pares clave-valor) si se tratan de un solo recurso o bien un array de estos diccionarios si es un conjunto de resultados. En el caso de que haya habido un error, devuelven el valor null. Para devolver esos datos al cliente REST, debemos darles el formato adecuado, bien sea XML o JSON. La conversión de un diccionario en JSON es trivial en PHP usando json_encode($array). Para hacer la conversión a XML necesitamos apoyarnos en una pequeña función recursiva como se muestra en esta respuesta de stackoverflow. Así es como quedaría el tratamiento de las peticiones post y put, en las que si todo es correcto devolvemos al cliente el único registro insertado o modificado, respectivamente.

$error = "";
if ($request_method == 'post') {
	$result = $this->post($error);
} else {
	$result = $this->put($error);
}

if($result) {
	if ($content_type == 'json')
	{
		RESTcontroller::sendResponse(200, json_encode($result), 'application/json');
	}
	else 
	{
		$xml = new SimpleXMLElement("<?xml version="1.0"?><$classname/>");
		RESTcontroller::array_to_xml($result, $xml);					
		RESTcontroller::sendResponse(200, $xml->asXML(), 'application/xml');
	}
} else {
	RESTcontroller::sendError(500, $error, $content_type);
}

Y este sería el código de nuestro método protegido para convertir un array en un documento XML:

protected static function array_to_xml($data, &$xml) {
	    foreach($data as $key => $value) {
	        if(is_array($value)) {
	            if(!is_numeric($key)){
	                $subnode = $xml->addChild("$key");
	                RESTcontroller::array_to_xml($value, $subnode);
	            }
	            else{
	                RESTcontroller::array_to_xml($value, $xml);
	            }
	        }
	        else {
	            $xml->addChild("$key","$value");
	        }
	    }
	}

El tratamiento que hacemos de la respuesta de la clase derivada de RESTController es ligeramente diferente, pues tenemos que devolver correctamente tanto registros individuales como conjunto de registros. La forma que tenemos de diferenciar ambos casos es preguntando si está definida una clave llamada ID en el diccionario. Si existe (en el primer ‘nivel’ de profundidad) estamos tratando un registro individual. En caso contrario se trata de un conjunto de ellos.

case 'get':
$error = "";
$result = $this-&gt;get($error);

if ($result) {
	if ($content_type == 'json')
	{
		 // Conjunto de conjunto de resultados		
		if (!array_key_exists("ID", $result)) {
			$result = array("ArrayOf$classname" =&gt; $result);
		}
		RESTcontroller::sendResponse(200, json_encode($result), 'application/json');
	}
	else
	{	
		// Consulta de un sólo elemento			
		if (array_key_exists("ID", $result)) {
			$xml = new SimpleXMLElement("<!--?xml version="1.0"?-->&lt;$classname/&gt;");
			RESTcontroller::array_to_xml($result, $xml);
		} else { // Conjunto de conjunto de resultados
			$xml = new SimpleXMLElement("<!--?xml version="1.0"?-->&lt;ArrayOf$classname/&gt;");
			foreach($result as $object) {
      				$subnode = $xml-&gt;addChild("$classname");
      				RESTcontroller::array_to_xml($object, $subnode);
			}					
		}

		RESTcontroller::sendResponse(200, $xml->asXML(), 'application/xml');
	}	
} else {
	RESTcontroller::sendError(500, $error, $content_type);
}
break;

En realidad, podríamos tratar peticiones get, post y put en un solo caso del switch, pero por claridad los vamos a mantener separado por ahora.

Por último, en las peticiones de tipo delete se devolverá un mensaje de OK si se ha completado la operación con éxito, y el error en caso contrario.

if($this->delete($error)) {
	if ($content_type == 'json')
	{
		RESTcontroller::sendResponse(200, json_encode(array("message" => "OK")), 'application/json');
	}
	else 
	{						
		RESTcontroller::sendResponse(200, "<?xml version="1.0"?><message>OK</message>", 'application/xml');
	}
	RESTcontroller::sendResponse(200);
} else {
	RESTcontroller::sendError(500, $error, $content_type);
}

El código de los métodos de clase sendResponse y getStatusCodeMessage es exactamente el mismo que el del artículo que mencioné arriba.

¿CÓMO SE UTILIZA ESTA CLASE ABSTRACTA?

Cuando diseñamos un servicio REST, normalmente servirá para proporcionar servicios para la manipulación de datos persistentes, almacenados en bases de datos SQL o no SQL. En ambos casos tendremos recursos que se corresponderán con tablas o colecciones. En cualquier caso, tendremos que proporcionar un recurso con un nombre determinado. Si queremos proporcionar servicios sobre un recurso llamado User, lo primero que debemos hacer es crear un fichero user.php que tendrá el siguiente aspecto inicial:

<?PHP
require_once('RESTcontroller.php');

class UserController extends RESTcontroller {
	function UserController() {
		$this->classname="User";
	}

	function get(&$error) {
		$error = '';
		$response = '':

		return $response;
	}

	function post(&$error) {
		$error = '';
		$response = '':

		return $response;
	}

	function put(&$error) {
		$error = '';
		$response = '':

		return $response;
	}

	function delete(&$error) {
		$error = '';
		$response = '':

		return $response;
	}
}

?>

En este fichero definimos una clase UserController heredada de la clase RESTController. Partiendo de esa plantilla, tendremos que escribir nuestro código en función de la lógica de nuestra aplicación y del motor de datos que tengamos debajo, en parte encapsulado por una clase RESTModel. Para continuar con esta entrada, vamos a suponer que trabajamos con una base de datos MySQL. De esta forma también podremos presentar la clase RESTModel. El código competo de nuestra clase UserController quedaría así:

<?PHP
require_once('RESTcontroller.php');
require_once('RESTmodel.php');

class UserModel extends RESTmodel {
	function UserModel() {
		$this->tablename = "Users";
		$this->properties["ID"] = 0;
		$this->properties["nick_name"] = "";
		$this->properties["password"] = "";
	}
}

class UserController extends RESTcontroller {
	function UserController() {
		$this->classname="User";
	}

	function get(&$error) {
		$model = new UserModel();
		$error = '';

		// Leer los datos de usarios, conocido su ID
		if (isset($this->ID)) {
			$model->properties["ID"] = $this->ID;
			$response = $model->select();	
			if (!$response) {
				$error = "Not found User with ID ".$this->ID; 
			}
		// Login
		} else if (isset($this->data["nick_name"]) && isset($this->data["password"])) {
			$nick_name = $this->data["nick_name"];
			$password = $this->data["password"];
			$response = $model->select("password='$password' AND nick_name='$nick_name'");
			if (!$response) {
				$error = "Authentication failed"; 
			}
		// Usuarios con nick similar a un nombre dado
		} else if (isset($this->data["name"]) ) {
			unset($model->properties["password"]);
			$name = $this->data["name"];
			$response = $model->selectAll("`nick_name` LIKE '%$name%'");
			if (!$response) {
				$error = "No users found"; 
			}	
		// Petición no reconocida
		} else {
			$response = false;
			$error = "No parameters";
		}

		return $response;
	}

	function post(&$error) {
		// Validamos los datos
		if (isset($this->data["password"]) && $this->data["password"] != "" &&
			isset($this->data["nick_name"]) && $this->data["nick_name"] != "") {	

			$model = new UserModel();					

			// Comprobamos que no exista ya un usuario con ese nick
			$response = $model->selectAll("`nick_name`='".$this->data["nick_name"]."'");	
			if ($response && count($response)>0) {
				$error = "User nick already exits";
				return false;
			} 

			// Copiamos los datos en las propiedades del modelo
			$model->properties["nick_name"] = $this->data["nick_name"];
			$model->properties["password"] = $this->data["password"];	

			$response = $model->insert();
			if ($response) {
				$error = "";
			} else {
				$response = false;
				$error = "Database Insert Error";
			}

		} else {
			$response  = false;
			$error = "Imcomplete User data";
		}	

		return $response;
	}

	function put(&$error) {
		$model = new UserModel();

		// Comprobamos si existe el usuario
		// y de paso precargamos los datos existentes
		$model->properties["ID"] = $this->ID;
		$found = $model->select();

		if ($found) {		
			// Cmabiamos los datos que hayamos recibido					 
			if(isset($this->data["password"]) && $this->data["password"] != "") {						
				$model->properties["password"] = $this->data["password"];	
			}

			$response = $model->update();
			if (!$response) {
				$error = "Database Update Error";
			}	
		} else {
			$response = false;
			$error = "Not found resource with ID ".$this->ID; 
		}
		return $response;
	}

	function delete(&$error) {
		$model = new UserModel();
		$model->properties["ID"] = $this->ID;
		$result = $model->delete();
		if ($result) {
			$error = "";
		} else {
			$error = "Error deleting User ".$this->ID;
		}

		return $result;
	}
}

En cada método he añadido los comentarios necesarios para entender el código. En el método get, en función de los parámetros recibidos se realiza una consulta u otra al modelo. En el método post, realizamos una validación de los datos obligatorios para hacer la inserción. En el método put, primero comprobamos que exista el registro, cargando de paso sus datos en las propiedades del modelo, y luego modificamos los datos que hayamos recibido en la petición, manteniendo el resto intacto. El método delete tiene poco que comentar.

Al principio del fichero hemos definido una clase derivada de la clase RESTModel. En ella definimos una propiedad llamada properties, que contiene un diccionario con los nombres de los campos de nuestra base de datos. Definimos además otra propiedad tablename que indica el nombre de la tabla que vamos a manipular. Mediante estas propiedades podemos crear de forma automatizada las consultas SELECT, INSERT, UPDATE y DELETE en la clase RESTModel. Esta clase además expone una serie de métodos que permite hacer estas operaciones básicas:

<?php

abstract class RESTmodel
{
	public $properties = array();
	protected $tablename;

	function update() {

	}

	function insert() {

	}

	function select($where = "") {

	}

	function selectAll($where = "") {

	}

	function delete() {

	}
}

?>

El funcionamiento de la clase RESTModel da para un futuro artículo. Antes de finalizar no hay que olvidar incluir el fichero user.php en index.html.

require_once('user.php');

Que aproveche.

Wanderer

Hace un tiempo hice el experimento de crear un juego en un rato. Estuve publicando mis progresos en twitter, pero de ahí se lo lleva el viento. Como quiero probar Calabash como framework para hacer TDD, he pensado que podría utilizar ese mini juego para ello. Aprovecho la ocasión para liberar con licencia MIT el código que resultó del experimento y anunciarlo aquí, junto con el vídeo que grabé para demostrar su funcionamiento.

Otra vez no…

restaurando_macosx La semana pasada empezó con el disco duro del portátil roto. Mi MacBook seguía funcionando pero de una forma muy degradada. Por suerte tengo un NAS donde TimeMachine hace las copias de seguridad. Salí corriendo a encargar en una tienda local un SSD de 128GB, pero como hasta hoy no me lo traían, opté por reciclar un disco de un NetBook caído en desgracia.

¿Y que tiene de interesante esta entrada? Pues cómo pude resolver algún problema y cómo no puede resolver otros. El primero con el que me encontré fue que la copia más actualizada de Mac OS X que tengo en CD es de Snow Leopard. No pasa nada, pensé, instalo y luego me paso a Maverick. Tras unas 16 a 18 horas de restauración del equipo desde Time Machine me encontré con el primer gran PROBLEMA: Las claves de los usuarios restaurados no eran reconocidas. Por lo visto, la forma en la que se gestionan la seguridad (claves, permisos, …) cambió a partir de Lion. La SOLUCIÓN fue comenzar de nuevo la instalación y crear un usuario temporal desde el que actualizar a Maverick, pasando de restaurar mis datos de usuario. Total, se trataba de un parche temporal.

windows_on_mac

En la actualización surgió el segundo PROBLEMA: La descarga de Maverick se quedó congelada, y la aplicación de la AppStore no paraba de fallar con botones “Descargar” que descargaban, parpadeos epilépticos, etc. Tuve la mala suerte de coincidir con el lanzamiento de la actualización 10.9.2 de Maverick. Después de probar varias soluciones, me tuve que crear un nuevo usuario con permisos de administrador, usar un App ID distinto para ese usuario y entonces sí descargar la actualización de Maverick. Otra cosa que hice fue pasar de la wifi y conectar directamente al router con un cable ethernet. Como la seda.

Como sabía que tenía que pasar de nuevo por todo el proceso de instalación esta semana con el disco SSD, tuve la precaución de crearme un USB “bootable” desde el que se puede instalar Maverick. De hecho así fue como finalmente hice la instalación la semana pasada.

En fin, espero que a alguien le sirva este post para no caer en los mismos problemas.

Calentador de velas

Últimamente se han visto muchos vídeos sobre la construcción de calentadores construidos con macetas de barro cuya energía proviene de unas pocas “velas de té”. Me pareció muy curioso y decidí construir uno con un diseño más o menos refinado. Yo opté por la variante que genera una corriente de convección. He aquí los pasos que seguí para construirlo.

ADVERTENCIA: Este invento en realidad NO FUNCIONA. Se necesitan unas 30 velas para que se pueda calentar una habitación.

Primer paso: Los materiales.

Hacen falta dos macetas de barro (dos tiestos). Una debe entrar dentro de la otra, dejando aproximadamente un centímetro de separación entre ellas. Yo como base he usado un plato de madera de los de servir pulpo, de un diámetro ligeramente superior al del tiesto mayor, para que sea estable. Para el soporte central hacen falta una barra roscada, tuercas y arandelas. Para dejar en su sitio la maceta mayor he usado unas alcayas (escarpias) bastante grandes. Herramientas al uso.

IMG_1489

 

Segundo paso: Preparar el soporte.

Hacemos un agujero en el centro con una broca pequeña para que nos sirva de guía. Luego, con una broca de pala de un diámetro mayor que el de las arandelas que estemos usando hacemos un rebaje para que la arandela y la tuerca no sobresalgan más del reborde del plato. En mi caso el rebaje llega hasta la mitad del grosor de la madera.

IMG_1492

Lo siguiente es colocar el tiesto pequeño en su sitio fijándolo provisionalmente con la barra roscada. Marcamos los tres puntos don irán las alcayatas.

IMG_1493

Con la broca pequeña hacemos unos agujeros ciegos (no pasantes) que nos sirvan de guía para colocar las alcayatas sin rajar la madera. Solo nos queda colocarlas, montar el tiesto pequeño con la barra roscada y las tuercas, y medir dónde debemos cortar la barra.

IMG_1497 IMG_1498

 

Tercer paso: Montaje completo.

Una vez cortada. Ya podemos montar completamente el calentador. Para no astillar o rajar el tiesto pequeño, yo decidí usar unas arandelas de goma recortadas de una pieza que compré hace tiempo para el montaje de la campana de “casi vacío”. Fue una mala idea, porque el tiesto se pone realmente caliente y el olor a goma quemada es importante. Ahora no las puedo retirar, porque se han fundido con la arandela y el tiesto. El centro lo recorté con un sacabocados.

IMG_1491

Nos tenemos que asegurar de que quede espacio suficiente ente los tiestos para que el aire circule, ascienda, y salga por el orificio superior del tiesto mayor. En otros diseños tapan ese orificio también. En ese caso sería un calentador más de tipo radiante, pero entonces no le veo sentido a usar dos tiestos (si alguien sabe el porqué…).

IMG_1494

 

Paso final: La prueba.

Por último colocamos la velitas de té y las encendemos. Los tiestos se ponen realmente calientes, pero no lo suficiente como para calentar una habitación. Hay que tener cuidado porque la base de madera también se calienta muchísimo. Habría que mejorar el diseño colocando un platillo metálico suspendido sobre la madera, sostenido por dos tuercas en la barra roscada.

IMG_1500

Fue una tarde divertida, aunque el resultado fuese algo decepcionante (Resultados que me lo esperaba por los cálculos de potencia que un amigo había hecho previamente).

Smultron

Smultron Logo

Hace años que uso un pequeño pero potente editor de texto para Mac OS X llamado Smultron. En su día fue gratuito y ha ido pasando de equipo a equipo gracias al maravilloso asistente de migración de Mac OS X. Ya estaba achacoso, y parece que no se llevaba muy bien con los 64 bits. Buscando una actualización que resolviera los problemas (hace tiempo que dejó de hacerlo sólo, el pobre) he descubierto que ahora es de pago. Lo he comprado muy gustosamente.

No hace mucho compré NeoOffice, para mi gusto el mejor “port” de OpenOffice para Mac OS X. RECORDAD: Hay que comprar el software y/o donar dinero a sus autores. El “pirateo” de software está mal.

A veces me aburro…

En realidad no. Si me aburro hago tontunadas como generar un gráfico estadístico aleatorio usando la librería libgd.

 

Posición inicial del juego
Use para su estadística inventada

Edito: Añado el código fuente:

<?php
$padding = 10;
$width = 500;
$height = 400;
$hor_div = 10;
$ver_div = 12;

header("Content-Type: image/png");
$im = @imagecreate($width, $height)
    or die("Cannot Initialize new GD image stream");
$color_fondo = imagecolorallocate($im, 230, 230, 255);

$color_texto = imagecolorallocate($im, 0, 0, 0);

imagerectangle ($im, $padding, $padding, $width - $padding, $height - $padding, $color_texto);

$step = ($height - $padding*2) / $ver_div;
for($y=$padding; $y<$width - $padding; $y+=$step) {
	imageline($im, $padding, $y, $width - $padding, $y, $color_texto);
}

$step = ($width - $padding*2) / $hor_div;
for($x=$padding; $x<$width - $padding; $x+=$step) {
	imageline($im, $x, $padding, $x, $height - $padding, $color_texto);
}

$color_graph = imagecolorallocate($im, 255, 0, 0);
$prev = rand($padding, $height- $padding);
for($x=$padding+$step; $x<=$width - $padding; $x+=$step) {
	$curr = rand($padding, $height- $padding);
	imageline($im, $x-$step, $prev, $x, $curr, $color_graph);
	$prev = $curr;
}

imagepng($im);
imagedestroy($im);
?>

Un juego en un rato

Hace mucho tiempo vi un juego en un parque de juego que me pareció curioso. Se trata de un juego de 4 en raya, en el que cada jugador mueve una de sus fichas por turno, sin límite de cambios de dirección o distancia. El juego se llama “Vagabundo” y es así:

Juego del vagabundo
Juego del vagabundo

En la foto se ve que se puede mover cómo la rejilla por la que se mueven las bolas es de 6×6 ranuras. Sin embargo en las instrucciones dibujan una rejilla de 8×8.

Pues bien, desde el primer momento pensé que sería divertido hacer un juego para móviles así. Esto fue hace cosa de un año. Hace unas semanas hice un prototipo rápido de la interfaz para iOS. Empleé una par de horas de una tutoría en las que me aburría mucho. En principio solo se podía mover una bola. Un par de ratos más, incluido el echado esta misma tarde, y ya muevo todas las bolas evitando que colisionen y todo:

Posición inicial del juego
Posición inicial del juego

Pues bien, me he propuesto hacer el experimento de realizar el juego “en un rato” y contarlo. No parto de cero, porque ya tengo código previo que reutilizaré de otros proyectos, incluido el del servidor (porque será un juego para dos jugadores on-line) que empecé a explicar hace ya unos meses.

Algunas bolas movidas
Algunas bolas movidas

A ver cómo sale el experimento. Podéis seguirlo en mi cuenta de twitter que también tengo algo abandonada.