20071219

El garatge GAYLOR



Aquí tenim les fotos del Parking GAYLOR del carrer Aribau de Barcelona.

La família GAYLOR esta d'enhorabona, els nois de MUCHACHADA NUI, els hi han fet propaganda gratuïta en aquest video.



Frases mítiques:


- Soy GAYLOR
- Pués yo soy GAYER

- A mi me gustan las tortillas, así... revueltas.
- Pues a mí me gustan los bollos !


Finalment s'ha resolt el dubte de si era GAYLOR o GAYLORD !

Un altre foto, amb una vista més general:

20071215

Desconecta tu teléfono fijo !


Acabo de decidir desconectar mi teléfono fijo.


Hechos:
- No tengo display en el teléfono fijo para mostrar si me entran llamadas de números ocultos o normales.
- Últimamente no paro de recibir llamadas de teleoperadoras (sobretodo con ofertas de ADSL, que pesaos)
- Las teleoperadoras hace unos meses que utilizan la táctica de poner un robot de llamadas (llamar y colgar cuando lo coges) para saber los hábitos de conducta de las posibles víctimas
- Dichos robots de llamadas son lo peor del mundo y ponen de una mala leche bestial...
- Acabo de llamar a Telefónica al 1004 y muy amablemente me han ofrecido un servicio de bloqueo de números ocultos por 6 euros de alta + 1,20 euros al mes - Me parece UNA PUTA ESTAFA que: pague por una linea, que esta siendo constantemente bombardeada por empresas de telemárketing, que a su vez pagan a telefónica para ocultar sus números y spamear impunemente a sus propios usuarios y encima tengan el morrazo de intentar cobrarte para bloquear llamadas con números ocultos.
- Si me dijeras, claro, es que no pueden bloquear todos los números ocultos porque técnicamente es imposible, o lo que sea... vale! Pero es que PUEDEN, pero claro, te quieren cobrar por ello, ENCIMA! - Después de explicarme la ESTAFA, la teleoperadora del 1004 me ha preguntado si quería contratar ADSL de Telefónica o IMAGENIO, para FLIPAR !
- También teniendo en cuenta que NI DIOS me llama ya al teléfono fijo (que sólo lo tengo porque es como un impuesto revolucionario de Telefónica por el ADSL)

He decidido que la única solución es la siguente:

Voy a desconectar todos los terminales de teléfono fijo que hay en casa, y por si acaso lo conectaré una vez al día para ver si tengo algún mensaje en el contestador (que amablemente ofrece Telefónica) o por si quiero hacer alguna llamada.

He creado esta campaña en facebook para que todos hagamos lo mismo.

Campaña "Desconecta tu teléfono fijo"

Esta no es una campaña para perjudicar a nadie (sólo a las teleoperadoras, que no me pillarán nunca en casa y espero que me eliminen de sus bases de datos de posibles clientes spameables).

YA SE CANSARAN (que cansinooooooooos) !

20071206

Google Chart API, sorprenent

Google no para de sorprendre'm

Google continua sent una companyia diferent, avui he vist a ajaxian.com una referència al Google Chart API

Es al·lucinant com una API tant potent es pot descriure amb una sola pagina d'HTML de manera clara i meridiana.

Aquí podeu veure un parell d'exemples:


helloWoWWa



helloOMATECH

Trobo a faltar support per POST, com a mínim no esta documentat...


UPDATE:

Ai, mira quina gracia, he fet un petit experiment i sembla que NO rula, el formulari amb method="POST" no funciona, pero amb method GET si.

Test form:


Chart type:
Chart size:
Chart Data:

20071122

Hayden i The National al Apolo

Aquest dissabte passat (17 de novembre del 2007) vaig tenir la sort d'anar al concert de Hayden i The National al Apolo Club.

Hayden es un cantautor mític per nosaltres de Toronto, Canada.

El seu primer single, September, es una de les meves cançons favorites "of all times".

Des que September era un hitazo han passat més de 10 anys, pero encara s'em posa la gallina de piel al sentirla.

Com a curiositat, al concert no va tocar "September" pero de totes maneres va valer molt la pena, i em va recordar vells temps, despres vem sopar un pop excel·lent amb l'Otto al bar del costat del Bagdad i vem acabar la nit prenent uns "Gin Tonics de Hendrix" al Negroni amb ell i la Paula.

Aquí us deixo uns videos gravats al concert i unes quantes fotos.










Hayden a la guitarra i armónica, primer plà

Hayden als teclats

Hayden a la guitarra

Hayden a la guitarra i tocant l'armónica alhora, un crack :)

The National

Lead Guitar i teclista al fons (també era violi) de The National

The National

El cantant de The National (1)

El cantant de The National (2)


PD: He recuperat el "September" a la palm, aixi com un cover de Hayden interpretant "Gouge Away" de Pixies, si "Gouge Away" ja es genial, no ho es menys el cover de Hayden, totalment recomenable !!!

20071120

La Generalitat de Catalunya encarrega enquestes que són fetes en Castellà

Avui m'han fet una enquesta telefònica a l'empresa, ens preguntaven sobre la evolució de les TIC a la nostra empresa, importacions, exportacions, facturació etc.

Fins aquí tot bé.

El problema ve quan m'anuncien que es tracta d'una enquesta de la Generalitat, però la operadora em parla en Castellà i no només això, sinó que davant la meva amable petició a que canvii al Català, m'informa que L'ARGUMENTARI DE LA ENQUESTA ESTÀ EN CASTELLÀ.

Com que la noia no tenia cap culpa, fins i tot m'ha explicat en Català el problema tot i que no era catalano-parlant, jo he accedit a fer la enquesta (en Castellà), però conec molts casos de gent que s'ha negat a fer enquestes en aquestes condicions i no sense raó.

Crec que el problema aquí el té PERSEO, la empresa de enquestes i la Generalitat per no controlar les subcontrates que realitza, que:


  1. No tenen profesionals que siguin capaços de fer un argumentari en català.

  2. No tenen profesionals que siguin capaços de emetre aquest argumentari en català.



Té tela, perquè després diguin que el Castellà esta perseguit !

20071106

How to generate a set of unique random strings in PHP



I'm amazed in my daily work of how useful and easy to use is PHP.

Today I've to generate 1.728 random strings of 9 characters each.

Each string must contain only a subset of alphanumeric characters, no zero, no Ç, no Ñ, etc.

Of course there must no be repeated strings in the 1.728 results.

I've added the constraint, don't repeat the same character inside an string, to avoid, results like "AAAbbbCCC" for example.

Let's code:


function get_result()
{
$valid_chars=array("1", "2", "3", "4", "5", "6", "7", "8", "9"
, "a", "b", "c", "d", "e", "f", "g", "h", "j", "k", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
, "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z");

$result=array_rand($valid_chars, 9);
$result_str='';
foreach ($result as $value)
{
$result_str.=$valid_chars[$value];
}
return $result_str;
}


this easy function does the following, first declare the array of allowed chars in the resulting string $valid_chars, using array_rand we obtain 9 keys to the array randomly generated, for example $result could be {7, 10, 14, 20, 22, 30, 35, 42, 49}

Then we loop through the keys with a foreach and simply obtain the character associated to the key and concatenate to the $result_str string.

Finally the body of the php:


$results=array();

for ($i=0; $i<=2000; $i++)
{
array_push($results, get_result());
}

$results=array_unique($results);

$cont=0;
$results_str='';
foreach ($results as $value)
{
$cont++;
$results_str.=$value.'
';

if ($cont>=1728)
{
break;
}
}
echo $results_str;


In this code we simply loop from 0 to 2000 calling the get_result() function and storing the result in an array.

Then we call the array_unique to avoid duplicated strings (for this reason we have generate a bit more than 1728 results) at this point $results have yet more than 1.728 valid and unique resulting strings.

Finally we loop through the array and break the loop when the limit of 1.728 strings are reached, adding to a resulting string each code, and then output the string.

Enjoy your new randomly generated codes !

20071029

ipsojobs return, devolviendo código a la comunidad

La gente de ipsojobs ha creado una categoría en su blog que se titula ipsojobs-return, que contiene artículos técnicos, tanto en inglés como en castellano sobre how-tos que se han usado en la página ipsojobs.com.

De momento, acaba de aparecer un segundo tutorial, explicando como crear un widget de tipo UWA (Universal Widget API) que se puede utilizar en NetVibes, en iGoogle y en nuestro propio blog.

El anterior artículo hablaba de como zippear y cachear los javascripts y los CSSs de una página para optimizar la descarga de un site.

ipsojobs.com es una bolsa de trabajo on-line especializada en trabajos urgentes y usa un modelo de administración distribuida remunerando a los administradores de cada ciudad utilizando google adsense.

Nuevo widget UWA para ipsojobs.com

Esta semana hemos estado preparando un widget UWA en ipsojobs, UWA significa "Universal Widget API" y es una especie de standard creado por netvibes para poder crear Widgets en cualquier plataforma (Netvibes, igoogle, opera, iPhone) una especie de "write once, run everywhere" que prometia Sun con Java en su momento pero aplicado al mundo de los Widgets.

Ya puestos a crear un widget, lo hemos creado con UWA, aunque es posible que si salen incompatibilidades debamos crear n-widgets para las n-plataformas sobre las que queramos desarrollar.

Ipsojobs UWA Widget in action

El widget pretende ser algo un poco más complejo que un simple lector de RSS, en concreto los objetivos del widget son:


  • Permitir seleccionar fácilmente la ciudad sobre la que queremos consultar las ofertas de trabajo de ipsojobs.

  • La selección de la ciudad debe ser "dinámica" dado que cada día aparecen ciudades nuevas no puede ser una lista estática.

  • Cuando estas viendo las ofertas de una ciudad siempre podrás cambiar a otra ciudad fácilmente.

  • El número de ofertas por ciudad debe ser personalizable.

  • Una vez seleccionada una ciudad el widget debe "recordar la preferencia" y mostrar las ofertas de la ciudad hasta que el usuario decida cambiarla.


Si quereis probarlo simplemente podéis visitar http://www.ipsojobs.com/widgets/uwa.html

El código del widget UWA es relativamente sencillo, se basa en un sólo fichero XHTML con todos los javascripts y los CSS incrustados.

Declaración:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:widget="http://www.netvibes.com/ns/" >
<head>


<meta name="author" content="Agusti Pons, omatech.com" />
<meta name="description" content="ipsojobs.com find jobs easy in your city" />


<meta name="apiVersion" content="1.0" />
<meta name="autoRefresh" content="20" />
<meta name="debugMode" content="true" />


<link rel="stylesheet" type="text/css" href="http://www.netvibes.com/themes/uwa/style.css" />
<script type="text/javascript" src="http://www.netvibes.com/js/UWA/load.js.php?env=Standalone">


De esta parte, sólo cabe destacar que se debe modificar el autor y la descripción así como el parámetro debugMode, que en producción deberá ser false. El debugMode=true es muy practico porque manda los mensajes de error a la consola del navegador y se puden consultar con el Firebug por ejemplo.

Javascripts útiles:


<script type="text/javascript">
<![CDATA[
function showhide(e)
{
//el = document.getElementById(e);
el = widget.body.getElementsByClassName(e)[0];
el.style.display = el.style.display == "block" ? "none" : "block";
}


function getlang()
{
return widget.lang.substr(0, 2);
}


function link(url)
{
if (widget && widget.openURL)
{
widget.openURL(url);
}
}


function getSelected(ctrl)
{
for(i=0;i
{
if(ctrl[i].checked)
{
return ctrl[i].value;
}
}
return '';
}


function setcity(url)
{
widget.setBody('<p>...</p>');
widget.setValue('url', url);
UWA.Data.getFeed(widget.getValue('url')+'?lang='+getlang(), ipsowidget.display);
}


function selectcity()
{
widget.setTitle('ipsojobs.com widget - setting...');
UWA.Data.getText('http://www.ipsojobs.com/api/controller.php?action=zones_sites_list&xsl=netvibes〈='+getlang(), ipsowidget.zones_sites_processor);
}


function replace(texto,s1,s2)
{
return texto.split(s1).join(s2);
}


function get_change_city()
{
var lang = getlang();
if (lang=='es')
{
return 'Cambiar ciudad';
}
if (lang=='ca')
{
return 'Canviar ciutat';
}
if (lang=='fr')
{
return 'Changer de ville';
}
else
{
return 'Select city';
}
}
]]>
</script>


Las dos funciones más interesantes son setcity() y selectcity() que detallo a continuación:


function setcity(url)
{
widget.setBody('<p>...</p>');
widget.setValue('url', url);
UWA.Data.getFeed(widget.getValue('url')+'?lang='+getlang(), ipsowidget.display);
}


Recibe como parámetro la url del RSS que nos han clicado en la pagina de selección de la ciudad, primero ponemos unos puntos suspensivos para indicar que estamos cargando (widget.setBody('<p>...</p>');) posteriormente actualizamos el valor de la preferencia url (recordad que es oculta y el usuario no la puede ver) con la instrucción widget.setValue('url', url); y finalmente cargamos el feed RSS en el body, fijaos que utilizamos la url de la preferencia que acabamos de actualizar pero le añadimos el parámetro lang basándonos en el language del navegador del usuario UWA.Data.getFeed(widget.getValue('url')+'?lang='+getlang(), ipsowidget.display);.

Para mostrar el RSS feed en el body fijaros que llamamos a la función display del widget que veremos más abajo declarada como ipsowidget.display = function(feed) esta función es muy parecida a la que se explica en el HOWTO de como mostrar un RSS en la web de Netvibes.


function selectcity()
{
widget.setTitle('ipsojobs.com widget - setting...');
UWA.Data.getText('http://www.ipsojobs.com/api/controller.php?action=zones_sites_list&xsl=netvibes〈='+getlang(), ipsowidget.zones_sites_processor);
}


La función selectcity, sólo tiene dos lineas, la primera modifica el título del widget widget.setTitle('ipsojobs.com widget - setting...'); indicando que no estamos en ningúna ciudad sino en la pantalla de setting. La segunda linea carga una url especial de ipsojobs que genera el html necesario para mostrar el seleccionable de las distintas zonas y ciudades UWA.Data.getText('http://www.ipsojobs.com/api/controller.php?action=zones_sites_list&xsl=netvibes〈='+getlang(), ipsowidget.zones_sites_processor); con el html resultante se llama a la función ipsowidget.zones_sites_processor que veremos más abajo y simplemente machaca el body con el nuevo html. Cabe destacar que el html contiene la lista de zonas y sus ciudades ocultas, al clicar sobre la zona se llama a la función showhide para mostrar las ciudades de esta zona. Con iGoogle he comprovado que el desplegado y el plegado no funcionan muy bien porque el widget no se redimensiona correctamente, en cambio si arrastras el titulo del widget como si lo fueses a reposicionar, entonces se recalcula la altura del mismo correctamente.

Preferencias y CSSs:


<title>ipsojobs.com widget
<link rel="icon" type="image/png" href="http://www.netvibes.com/favicon.ico" />


<widget:preferences>
<preference name="url" type="hidden" label="URL" defaultValue="" />
<preference name="limit" type="range" label="Number of items to display" defaultValue="10" step="1" min="1" max="25" />
</widget:preferences>


<style type="text/css">
/* your CSS rules */


body {
height: 400px;
}


a:hover {
cursor: pointer;
}


h2 {
color: #8CC402;
}


h3 {
color: #8CC402;
}


</style>

Aquí podemos ver que creamos una preferencia llamada url de tipo hidden, es la que nos servira para almacenar la url del recurso RSS de la ciudad seleccionada. También creamos el parametro limit que permitirá al usuario seleccionar el numero de ofertas a mostrar en el rango de 1 a 25.

El meollo de la cuestión:


<script type="text/javascript">
<![CDATA[
var ipsowidget = {}


ipsowidget.feed = false;

ipsowidget.display = function(feed)
{
// get the number of items to display
widget.preferences[1].max = feed.items.length;


var toolbar=widget.createElement('h2');
var website_url=replace(widget.getValue('url'), '/rss/controller.php', '');
toolbar.setHTML(''+feed.title+'');


var toolbar2=widget.createElement('h3');
toolbar2.setHTML(''+get_change_city()+'');


widget.setTitle('ipsojobs.com - '+feed.title);

// create the 'ul' element, applying it the CSS class 'nv-feedList'
var feedList = widget.createElement('ul');


// your 'ul' element MUST make use of the 'nv-feedList' class
// to ensure your widget uses the UWA UI library
feedList.className = 'nv-feedList';


// number of parsed items
var j = 0;


// loop through the downloaded items
for(var i=0; i < feed.items.length; i++)
{
// if the limit is reached, stop looping
if (j >= widget.getValue('limit')) break;


// for each item, create the 'li' element
var item = feed.items[i];
var li = widget.createElement('li');


// create and fill the 'a' element of the item with the item's link
var a = widget.createElement('a');
a.href = item.link;


// fill the 'a' element with the item's title
var displayTitle = item.title;
a.innerHTML = displayTitle;


// build the title from the 255 first characters of the content
// remove the content's HTML tags along the way
var title = item.content.stripTags().truncate(255);
a.title = title;


// set a tooltip on the 'a' element, with the item's content
a.onmouseover = function()
{
UWA.Utils.setTooltip(this, this.content, 250);
}


// finally append the 'a' element we just filled, into the 'li' element
li.appendChild(a);


// ...and append the 'li' element to the main 'ul' element
feedList.appendChild(li);
j++;
}


var general=widget.createElement('div');
general.appendChild(toolbar);
general.appendChild(toolbar2);
general.appendChild(feedList);
// once the needed items have been parsed,
// send the main 'ul' element to the HTML body tag
widget.setBody(general);
}


ipsowidget.zones_sites_processor = function(text)
{
widget.setBody(text);
}


widget.onLoad = function()
{
if (widget.getValue('url')=='')
{
selectcity();
}
else
{
//alert(getlang());
UWA.Data.getFeed(widget.getValue('url')+'?lang='+getlang(), ipsowidget.display);
}
}
]]>
</script>


La mayoría de este código es muy parecido al HOWTO de como hacer un RSS widget con UWA (solucionando algún pequeño bug) con las siguientes diferencias:


var toolbar=widget.createElement('h2');
var website_url=replace(widget.getValue('url'), '/rss/controller.php', '');
toolbar.setHTML(''+feed.title+'');


var toolbar2=widget.createElement('h3');
toolbar2.setHTML(''+get_change_city()+'');


widget.setTitle('ipsojobs.com - '+feed.title);


En este fragmento creamos el elemento DOM que nos muestra el nombre de la ciudad seleccionada (con un link a la misma) y el elemento que nos permite cambiar de ciudad. En la última linea también actualizamos la barra de título del widget con el nombre de la ciudad seleccionada.

Al final, hemos añadido los fragmentos DOM creados.

var general=widget.createElement('div');
general.appendChild(toolbar);
general.appendChild(toolbar2);
general.appendChild(feedList);
// once the needed items have been parsed,
// send the main 'ul' element to the HTML body tag
widget.setBody(general);


El onLoad también esta un poco tuneado, en el ejemplo siempre carga la url, pero en nuestro caso puede ser que el widget se haya instalado por primera vez y no tengamos ninguna url en concreto, por eso hacemos lo siguiente:


widget.onLoad = function()
{
if (widget.getValue('url')=='')
{
selectcity();
}
else
{
//alert(getlang());
UWA.Data.getFeed(widget.getValue('url')+'?lang='+getlang(), ipsowidget.display);
}
}


Simplemente detecta si ya tenemos una url fijada y sino llamamos a selectcity que ya se encarga de hacer la llamada AJAX correspondiente para mostrar el selector de ciudades. En caso contrario (este usuario ya tenia la preferencia url fijada para este widget) simplemente la cargamos llamando a UWA.Data.getFeed, fijaros que obtengo el lenguaje del navegador y intento llamar con el lenguaje más apropiado al RSS que me interesa.

Finalmente el body de la página


</head>
<body>
<p>Welcome to the ipsojobs.com widget </p>
<p>...</p>
</body>
</html>


Esta parte no tiene misterio, simplemente mostramos un body, que en seguida se machacará con la función widget.onLoad, que hemos visto más arriba.

20071011

Cache and GZIP your javascripts and CSSs files to speed up your site



I've been trying to mix different sources to optimize the download speed of the javascript files and the CSS files of any web application, in particular I've worked for the IPSOJobs new urgent job bank web page, but it can be applicable in a more general way.

Your Web application can use this files if:


  • You can use .htaccess in your hosting

  • You have CSS only and JS only folders to apply to the whole folder

  • You can use PHP in your hosting



If all the above conditions are met, you can simply add three files to your CSS and/or JS folder and you are done.

Please, take with caution and do some testing, don't use directly in a production environment.


Of course, I'll not give any waranty of succes and you have to check the results using the Firebug Extension of Firefox, the "Live HTTP Headers" extension and the YSlow plugin of the Firebug Extension.

First file .htaccess:
Modify your .htaccess file to include the following:


AddHandler application/x-httpd-php .css .js
php_value auto_prepend_file gzip-start.php
php_value auto_append_file gzip-end.php


This code, tells Apache to automatically run the gzip-start.php before the requested javascript or css file and to run the file gzip-end.php after the conclusion of the requested file.

It's a powerful way to create common headers and footers to pages or files, but be aware that it comes at a cost, it's more fast to serve the static file alone than to run an php script before and one after the file, of course, you have to do some testing and see if it's worthy to do so.

Second file, the magical gzip-start.php:



function get_http_mdate()
{
return gmdate('D, d M Y H:i:s', filemtime($_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'])).' GMT';
}

function check_modified_header()
{// This function is based on code from http://ontosys.com/php/cache.html
$headers=apache_request_headers();
$if_modified_since=preg_replace('/;.*$/', '', $headers['If-Modified-Since']);
if(!$if_modified_since)
{
return;
}

$gmtime=get_http_mdate();

if ($if_modified_since == $gmtime)
{
header("HTTP/1.1 304 Not Modified");
exit;
}
}

check_modified_header();

// Open a gzipped buffer
ob_start ("ob_gzhandler");

if (strpos($_SERVER['PHP_SELF'], '.js')>0)
{// Javascript file
header("Content-type: text/javascript");
}
elseif (strpos($_SERVER['PHP_SELF'], '.css')>0)
{// CSS file
header("Content-type: text/css");
}

$offset = 60000000; // Far far away in time

// Expires
header("Expires: ".gmdate("D, d M Y H:i:s", time() + $offset) . " GMT");

// Cache-Control
header("Cache-Control: must-revalidate, max-age=".(time()+$offset));

header("Last-Modified: ".get_http_mdate());

// generate unique ID, using the modification date and the absolute path to the file
$hash = md5(filemtime($_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']).$_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']);
header('Etag: "'.$hash.'"');

?>


The concept is clear, this file is interpreted by the PHP runtime rigth before the output of the requested file.

Let's see the different parts of the file:


check_modified_header();


This function looks for the modification date of the requested file (filemtime($_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'])) and returns a HTTP 304 (Not Modified) if the file is fresh, to do that, first looks for a request header If-Modified-Since and then compare the dates.


// Open a gzipped buffer
ob_start ("ob_gzhandler");

if (strpos($_SERVER['PHP_SELF'], '.js')>0)
{// Javascript file
header("Content-type: text/javascript");
}
elseif (strpos($_SERVER['PHP_SELF'], '.css')>0)
{// CSS file
header("Content-type: text/css");
}


These lines opens a PHP buffer with the trick that it's using GZip compression, this is a very good feature of PHP that enables you to output gzipped content without any modification. Afterwards we put the Content-Type of the resulting file, depending of the extension of the file we put text/css or text/javascript.


$offset = 60000000; // Far far away in time

// Expires
header("Expires: ".gmdate("D, d M Y H:i:s", time() + $offset) . " GMT");

// Cache-Control
header("Cache-Control: must-revalidate, max-age=".(time()+$offset));


These lines put the Expires and Cache-Control headers, both far away in time, we create the variable offset with a constant 60 million seconds (about 2 years) and use that to generate a Expires header and a Cache-Control header with the value of two years in the future.

Be warned, your CSS and your JS files will be cached in a lot of proxies and client browsers, you have to use a "rename file policy" in your HTML to prevent the users from using old versions of the files. We've got little javascripts and css files to change, but I recommend to split these kind of files in different folders, for instance /js/usually-modified/omatech.js and apply only the caching technique to the folder usually-modified, then rename each time the .js file with a timestamp, say omatech_20071010.js, and change your html code to reflect the new version.



header("Last-Modified: ".get_http_mdate());

$hash = md5(filemtime($_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']).$_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF']);
header('Etag: "'.$hash.'"');


The last lines, creates a Last-Modified header, used to indicate the client browser the freshness of the file for future requests, this have interactions with the Cache-Control/max-age and the Expires headers (out of the reach of this post).

Finally we generate an unique Etag header, based on the update time of the requested file and it's full path.


Third and last file, the not less magical gzip-end.php:


header('Content-Length: ' . ob_get_length());
ob_end_flush();
?>


This file simply creates dinamically a Content-Length header with the size of the gzipped buffer we have been using for this request, and then flushes it's contents.

Simple eh ?


I hope you enjoyed and finded useful, feel free to change and play with the code.


I would like to thank the sources where I took inspiration and code:

The tutorial of CSS compression,
Facilitate User Experience with CSS Compression, from Max Kiesler

Good introduction to the problem of speeding up the webpages through caching and zipping javascripts
Serving Javascript Fast, by Cal Henderson

And always a good tutorial even for novices (in Spanish)
¿Por qué y cómo crear un espacio web "cache friendly"? from jcea

20071010

Fascicles de setembre del 2007

Una vegada passat setembre, sempre m'agrada posar la llista de fascicles que he vist anunciats a la tele, de fet les normes son, que els hagi vist a la tele i que m'hagi enrecordat d'apuntar-los :)

Potser aquest any que ja estic definitivament enganxat a la FOX i al AXN fins al punt que no veig gairebé mai les altres cadenes, no he pogut recopilar tots els que han sortit.


Fascicles d'aquest any:


  • Santísima Trinidad

  • Los cuentos de Calleja

  • Cantiflas

  • Formula 1 - SuperSlot

  • Leyendas de Le Mans

  • Stephen King

  • Las tortugas ninja

  • Scalextrix Seat Sport

  • Curso de Ingles de PlanetaAgostini

  • Mickey GEO

  • Ferrari

  • Urgencias en DVD

  • Pilates

  • Biblioteca de Cesar Vidal

  • Monta tu Dinosaurio

  • Lo mejor de la Zarzuela en DVD

  • Erase una vez El Cuerpo Humano

  • Tarta de Fresa

  • Transformers

  • Punto de cruz

  • Las 3 mellizas

  • Pokemon en DVD

  • Monta tu casa Andaluza

  • Guia Esencial de Belleza

  • Curso practico de Pilates

  • Tiranosaurio Rex

  • Los crimenes de Agatha Christie

  • Desafíos Matemáticos

  • La energía de las piedras




TOTAL: 29

Aquí podeu trobar:

20070908

Avui arranca IPSOJOBS, un nou concepte de borsa de treball on-line



Avui arranca IPSOJOBS un projecte intern d'Omatech que esdevindrà el líder en el mercat (poc explorat) de les feines urgents.

IPSOJOBS, te una orientació clarament global, inicialment traduït l'interface en català, castellà, anglés, xines i japones, permet introduïr o cercar ofertes de feina a Barcelona, Girona, Kyoto, Madrid, New York i Shanghai.



El creixement de la web l'estem basant en el que jo anomeno "Greedy Grow" que es basa en que la gent que vol guanyar diners gestionant una bossa de treball IPSOJOBS a la seva ciutat o area pot guanyar d'un 50% a un 100% de la publicitat generada pel seu "IPSOJOBS site", nomes cal que ens possem en contacte i ens doni les seves dades i el seu codi d'adsense de google, per més informació

20070830

Simple substring-before function in php


function substring_before($haystack, $needle)
{
if ($i=stripos($haystack, $needle))
{// Needle found, return from start to needle
return(substr($haystack, 0, $i));
}
else
{// Needle not found
return $haystack;
}
}


Really need an explanation ?

20070829

How to create a simple code checking process in PHP

The other day I was wondering exactly where a call to a function named "get_message" is used in all our php files and xsl files, it's easy to find using some advanced text editor like notepad++ and it's "search in files" functionality.

But, the problem was, I doesn't only need to know where are the calls, I need to know what parameter are used in each call, for example, get_message('HEADER') or get_message('KEYWORDS'), and afterwards I need to check the database to see if the given message (HEADER and KEYWORDS) is inserted there or not.

Of course, do that manually is a very, very, time consuming task, for that reason if prepared a code checking php that can save your day in similar problems.

First, let's create a structure:


function check_dir ($dir_name, $recursive)
{
$handle=opendir($dir_name);
if ($handle)
{
while (false!==($file=readdir($handle)))
{ if (is_file($dir_name.'/'.$file))
{// It's a file
if (substr($file, -3)=='php' && substr($file, 0, 1)!='.')
{// PHP file detected (the second condition avoids MAC temporary files to be checked)
check_php($dir_name.'/'.$file);
}
if (substr($file, -3)=='xsl' && substr($file, 0, 1)!='.')
{// XSL file detected (the second condition avoids MAC temporary files to be checked)
check_xsl($dir_name.'/'.$file);
}
}
}
if ($recursive)
{// The parameter tell us to look for subfolders
closedir($handle);
$handle=opendir($dir_name);
while (false!==($file=readdir($handle)))
{// Loop through the files
if (is_dir($dir_name.'/'.$file))
{// It's a folder
if ($file!='.' && $file!='..')
{// Check the next subfolder, avoiding the current and the parent folders
check_dir($dir_name.'/'.$file, $recursive);
}
}
}
}
closedir($handle);
}
else
{
echo 'I cannot open the folder '.$dir_name;
echo chr(13).chr(10).'
';
}
}



This function loops thought an initial folder and, if the second parameter is set to true, continues checking the directory hierarchy.

There are two functions to check the PHP files and the XSLs files, you can extend this checking to whatever kind of files you want.

Let's see the check_php function:


function check_php($file_path)
{
$file=fopen($file_path,'r');
while(!feof($file))
{// Loop until the end of the file
$line=fgets($file); // read line by line
if (preg_match('/get_message[ ]*\(\'([A-Z_]*)\'\)/', $line, $resultats)>0)
{
array_push($GLOBALS['messages_php'], $resultats[1]);
}
$GLOBALS['cont_lineas_php']++;
}
fclose($file);
}


As you can see in this simple but powerful code, we loop thought the php source file, line by line, and only whith a single if condition check if the line contains a get_message and take the parameter as the result of the evaluation of the regular expression.

This requires further explanation:

preg_match, takes a regular expression as first argument, then checks this regexp against the second argument ($line in the example) and put the resulting part of the evaluation (if any) in an array (the third parameter $resultats in our example). The function returns 0 if no matches where found or the number of matches instead.

The regular expression needs too a little bit of explanation, creating a regex from scratch is relatively simple, but it's a tricky language and very difficult to maintain:

- The regular expression starts with "/" and ends with "/" (first mistery solved)
- "get_message" this is a literal that we are looking for in the input
- "[ ]*" this means that we expect none or any number of whitespaces in the input just after the get_message array, this is for avoid the problem of undetecting some calls like "get_message ('blah')" or "get_message ('blah')" instead of the commonly used "get_message('blah')"
- \(\' and \'\) simply used to detect the string opening with (' and ending with ') the backslashes simply are the escape characters of the regular expressions.
- ([A-Z_]*) Thats the core of the regexp we are trying to create, simply indicates that we are looking for any combination of uppercase letters "A-Z" and underscores "_", the square brackets indicates the different permutations and the star means zero or more characters in the combination. Last but not least, the enclosing parenthesis makes the included combination a result of the regular expression evaluation, only the parenthesized part of the regexp can be taken after the evaluation as part of the result, that is the part that is returned to the $resultats array when finished.

The theory explained, let's look for a couple of examples:
$keywords=get_message ('KEYWORDS'); --> return 1 and $result is an array containing the value KEYWORDS
$description=get_message('DESCRIPTION'); --> return 1 and $result is an array containing the value DESCRIPTION
$hello_world=get_message('HELLO_WORLD'); --> return 1 and $result is an array containing the value HELLO_WORLD
$hola = 'hola'; --> return 0

Additionally we increase the global counter of php lines in all the application with the line $GLOBALS['cont_lineas_php']++;

The check_xsl function is very similar to the check_php function only looking for a different regular expression and updates other variables:


function check_xsl($file_path)
{
$file=fopen($file_path,'r');
while(!feof($file))
{
$line=fgets($file);
if (preg_match('/[ ]*([A-Z_]*)0)
{
if (!stripos($line, ' {
array_push($GLOBALS['messages_xsl'], $resultats[1]);
}
}
$GLOBALS['cont_lineas_xsl']++;
}
fclose($file);
}



Now let's look for the part where we call the functions:


check_dir($_SERVER['DOCUMENT_ROOT'], false);
check_dir($_SERVER['DOCUMENT_ROOT'].'/actions/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/admin/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/ajax/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/batchs/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/captcha/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/conf/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/models/', true);


check_dir($_SERVER['DOCUMENT_ROOT'].'/rss/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/styles/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/utils/', true);
check_dir($_SERVER['DOCUMENT_ROOT'].'/views/', true);

echo 'PHP LINES: '.$GLOBALS['cont_lineas_php'];
echo chr(13).chr(10).'
';
echo 'XSL LINES: '.$GLOBALS['cont_lineas_xsl'];
echo chr(13).chr(10).'
';
echo chr(13).chr(10).'
';


This calls simply check all the directories I needed to check and output the number of lines of php and xsl that we have.

Finally we want to do a more sophisticated analysis with the data we have collected, we want to look if all the messages collected in
the arrays $GLOBALS['messages_xsl'] and $GLOBALS['messages_php'] really exists in the database and report if there are some inexistent (which is an error and must be solved)


$unics=array_unique(array_merge($GLOBALS['messages_php'], $GLOBALS['messages_xsl']));
$no_existents=array_filter($unics, 'not_exist_message');
echo 'NONEXISTING MESSAGES IN THE DB: '.count($no_existents);
echo chr(13).chr(10).'
';
echo implode($no_existents, ', ');
echo chr(13).chr(10).'
';
echo chr(13).chr(10).'
';

echo 'UNIQUE MESSAGES IN GENERAL: '.count($unics);
echo chr(13).chr(10).'
';
echo implode($unics, ', ');
echo chr(13).chr(10).'
';
echo chr(13).chr(10).'
';


The first line merges the two arrays with array_merge, then generates an unique array and put it into $unics variable.

The second line filters the $unics array with a custom function that checks the database for this message in particular, here is the function:


function not_exist_message ($value)
{
return(!exist_message($value));
}

function exist_message ($value)
{
$sql='select count(*) num
from messages m
where codi="'.$value.'"
';

$dbh=get_db_handler();
$result = mysql_query($sql, $dbh);
if(!$result)
{
return false;
}
$row = mysql_fetch_array($result, MYSQL_ASSOC);
return($row['num']>0);
}


The array_filter, runs the function in the second parameter thought each element of the array, and the resulting array contains only the elements that the function evaluates as true. The function exist_message simply executes an sql statement that counts the number of occurrences of the given message in the database.

That's all, for completeness here is the initial part of the declaration of variables and includes and so on:


require_once($_SERVER['DOCUMENT_ROOT'].'/conf/ompDB.php');

echo 'Code control report:';
echo chr(13).chr(10).'
';

$GLOBALS['cont_lineas_php']=0;
$GLOBALS['messages_php']=array();
$GLOBALS['cont_lineas_xsl']=0;
$GLOBALS['messages_xsl']=array();


And a sample of output generated by the execution of the php file:


Code control report:
PHP LINES: 7886
XSL LINES: 992

NONEXISTING MESSAGES IN THE DB: 28
HEADER_CENTRAL_EDITABLE_POSTS_CLEAR, STATIC_HEADER_HOW_IT_WORKS, STATIC_CONTENT_HOW_IT_WORKS, HEADER_MESSAGE_ADD_POST, STATIC_HEADER_FOLLOW_OFFERS, STATIC_CONTENT_FOLLOW_OFFERS, EXPLICATION_RSS_LINK_CITY, EXPLICATION_RSS_LINK_CATEGORY, SECURITY_ERROR_HEADER, SECURITY_ERROR, SECURITY_ERROR_NOT_EDITABLE, EDIT_YOUR_POST, POST_UPDATED, POST_UPDATED_LONG, POST_UPDATE_ERROR, POST_UPDATE_ERROR_LONG, HEADER_POST_SAVED_ERROR, ERROR_POST_UNKNOWN, ERROR_SITE_UNKNOWN, SUBJECT_SEND_TO_A_FRIEND, PREBODY_SEND_TO_A_FRIEND, POSTBODY_SEND_TO_A_FRIEND, MESSAGE_SENT_SUCCESFULLY, MESSAGE_SENT_ERROR, EXPLICATION_RSS, EXPLICATION_CITIES_RSS, EXPLICATION_CATE_RSS, EDITABLE_POST_LINK

UNIQUE MESSAGES IN GENERAL: 123
LANGUAGE_NOT_SUPPORTED, LANGUAGE_CHANGED, TITLE, ADD_POST_SINGLE, ADD_POST, EDITABLE_POSTS, EDITABLE_POSTS_CLEAR, HEADER_CENTRAL_EDITABLE_POSTS_CLEAR, HEADER_SEARCH, SEARCH_ERROR, STATIC_HEADER_WHO_WE_ARE, STATIC_CONTENT_WHO_WE_ARE, STATIC_HEADER_CONDITIONS, STATIC_CONTENT_CONDITIONS, STATIC_HEADER_WHAT_IS, STATIC_CONTENT_WHAT_IS, STATIC_HEADER_HOW_IT_WORKS, STATIC_CONTENT_HOW_IT_WORKS, DONE, CATEGORY_NEEDED, TITLE_NEEDED, DESCRIPTION_NEEDED, CONTACT_NEEDED, SECURITY_CODE_NEEDED, HEADER_MESSAGE_ADD_POST, INSERT_YOUR_POST, POST_SAVED, POST_SAVED_LONG, POST_SAVE_ERROR, POST_SAVE_ERROR_LONG, HEADER_CENTRAL_ADD_POST, STATIC_HEADER_FOLLOW_OFFERS, STATIC_CONTENT_FOLLOW_OFFERS, EXPLICATION_RSS_LINK_CITY, EXPLICATION_RSS_LINK_CATEGORY, HEADER_CENTRAL_EDIT_POST, SECURITY_ERROR_HEADER, SECURITY_ERROR, SECURITY_ERROR_NOT_EDITABLE, EDIT_YOUR_POST, POST_UPDATED, POST_UPDATED_LONG, POST_UPDATE_ERROR, POST_UPDATE_ERROR_LONG, HEADER_CENTRAL_EDITABLE_POSTS, HEADER_CENTRAL_HOME, HEADER_CENTRAL_POST, HEADER_POST_SAVED, HEADER_POST_SAVED_ERROR, GO_TO, HEADER_CENTRAL_CATEGORIES, REPORT_POSTED, REPORT_NOT_POSTED, FLAG_SHORT, MOTIVES, REPORT, SEND_SHORT, NAME_EMAIL, FRIEND_EMAIL, MESSAGE_EMAIL, SUBMIT_EMAIL, ACTIVE_POSTS, LAST_ACTIVE_POST, CITY, POST_DETAIL_FLAG_INCORRECT, POST_DETAIL_FLAG_CORRECT, ERROR_POST_UNKNOWN, ERROR_NAME_EMAIL, ERROR_FRIEND_EMAIL, ERROR_MESSAGE_EMAIL, ERROR_SITE_UNKNOWN, SUBJECT_SEND_TO_A_FRIEND, PREBODY_SEND_TO_A_FRIEND, POSTBODY_SEND_TO_A_FRIEND, MESSAGE_SENT_SUCCESFULLY, MESSAGE_SENT_ERROR, TIME_DAYS, TIME_DAY, TIME_HOURS, TIME_HOUR, TIME_MINUTES, TIME_MINUTE, TIME_FEW, SEARCH_BOX_TEXT, BUTTON_SEARCH, HEADER_CITIES, HEADER_AD, GLOBAL_SELECT_LANG, GLOBAL_SELECT_CITY, STATIC_WHO_WE_ARE, STATIC_BLOG, STATIC_CONDITIONS, STATIC_WHAT_IS_IPSO, HEADER_CATEGORIES, HOME_SELECT_CITY, HOME_CITIES, HOME_LANGUAGES, HEADER_TITLE_HOME_OFFER, VIEW_DETAIL, POST_CATEGORY, POSTED, NO_POST_IN_SEARCH, POST_TITLE, POST_TITLE_EXPLAIN, POST_CATEGORY_EXPLAIN, POST_DESCRIPTION, POST_DESCRIPTION_EXPLAIN, POST_CONTACT_CONDITIONS, POST_CONTACT_CONDITIONS_EXPLAIN, CAPTCHA, CAPTCHA_EXPLAIN, POST_SUBMIT_BUTTON, EXPLICATION_RSS, EXPLICATION_CITIES_RSS, EXPLICATION_CATE_RSS, EDITABLE_POST_LINK, NO_POST_IN_CATEGORY, RELATED_POSTS, FLAG_LONG, SEND_LONG, VIEWED, TIMES, CATEGORIES


Ways to improve:
- We must upgrade the code count of lines avoiding whitespace-only lines and commented lines.

That's all folks

20070821

Cumpleaños feliz para la cheerleader de Heroes



Hoy es un gran dia para los seguidores masculinos de la serie Heroes, Hayden Panettiere, la actriz que encarna a Claire la famosa Cheerleader de la serie cumple 18 años.

Para todos aquellos que han tenido fantasias con esta chica, felicidades, ya son legales (por lo menos en gran parte del mundo)

:)

Ah, felicidades para ti también, Hayden !

20070813

Harry Potter via amazon.com


El mateix dia 21 de juliol vaig fer la comanda de l'últim volum de Harry Potter (and the deathly hallows).

El dijous em va arribar de Amazon US (vaig ser tonto de no demanar-lo a UK) i vaig flipar amb el packaging especial que portava.

Als costats posava "HARRY POTTER AND THE DEATHLY HALLOWS" i "YEAR 7" respectivament i a la part d'adalt sortia el típic mussol missatger.

Lo millor eren els missatges de warning:

ATTENTION MUGGLES - DO NOT DELIVER OR OPEN BEFORE JULY 21!

BRUTAL !!!




A part em vaig demanar dos llibres més (Fast food nation i On intelligence) pero els de amazon son la polla i van fer dos enviaments, un amb el packaging especial de Harry Potter i l'altre standard.

Això es customer care, lo demés son tonteries !



20070726

Meneame caido



Es raro en meneame tener downtime, pero cuando lo tienen lo hacen con estilo, como mínimo no se ve tanto como el plumber de bloglines i el gatito de twitter...

De hecho podeis continuar viendo la pagina de error cuando querais en lounge

20070621

Si els herois fossin programes o sistemes

L'Oriol m'ha passat aquestes dues imatges, comparant els Heroes, de la serie, amb sistemes o programes informàtics, fins i tot amb companyies del sector.






Claire Bennet - RAID1 (mirroring)
Hiro Nakamura - Pause key + System Restore Key
Sr. Bennet - Administrador de tareas
Ando Masahashi - Scroll Lock (Next to Pause Key)
Mohinder Suresh - Wikipedia
Nikki Sanders - Dual Boot
Nathan Petrelli - On-the-fly
Peter Petrelli - Copy & Paste
Micah Sanders - The IT Guy
Matt Parkman - Port Listener
Isaac Mendez - Adobe Photoshop
Sylar - Google
D.L. Hawkins - Trojan Horse
Eden McCain - Sudo
El Haitiano - Firewall + Supr Key
Ted Sprage - Overclocking
Candice Wilmer - Skins
Lindermann - Recovery CD

20070531

Ja arriba el "Primavera Sound 2007"

Avui comencen els concerts principals del Primavera 2007, aquest vídeo reflexa força bé l'esperit del festival :) (gracias María por pasarmelo)



Els concerts on em podreu trobar (si el cos aguanta) son els següents (per ordre de actuació)


  • Veracruz

  • The Smashing Pumpkins

  • The White Stripes

  • Sr. Chinarro

  • Los Planetas

  • Ted Leo & The Pharmacists

  • The Long Blondes

  • Architecture in Helsinki

  • The Good The Bad & The Queen

  • Sonic Youth

  • Wilco



Ens veiem al Fórum !

20070525

Campaña "Hijo de puta" a Eurovisión 2008



Si intentaste no saber que era el puto "Desafío Español" hasta que ya te lo metían hasta en la sopa.
Si crees que Eurovisión se esta convirtiendo en una pandilla de freakis cantando y te alegras de ello.
Si eres fan de la hora chanante y te preocupa que se convierta en mainstream al pasar a la 2.

Esta es tu web.

Desafío Español "Hijo de Puta" a Eurovisión 2008

http://desafio-espanyol-hijo-de-puta-a-eurovision-2008.com/

El auténtico "Desafío"

Saludos
Friky.blogspot.com


Meneamela

20070524

Sclipo guanya el concurs startup 2.0




El concurs per trobar la millor startup 2.0 ha sigut adjudicat a sclipo.com aka visuarios.com

Felicitats a tot l'equip, Gregor, Otto, Xevi, Sebas, Sergi, Dan i la resta.

Omatech.com
va realitzar el desenvolupament inicial de visuarios.com i ja fa uns mesos que volen sols amb un equip autónom.

Això dona anims per continuar, seguiu així !!!

Aquí la entrada del twitter anunciant al guanyador.

20070522

Adsense per fi en Català



Google s'ha apiadat de tots els bloggers i webmasters de catalunya, després de rebre moltes protestes per part de la comunitat de webs catalanes.

Aquí la noticia del blog de adsense.

Hi han hagut casos de bloggers que havien deixat d'escriure en català ja que no podien posar adsense, jo vaig tenir sort, perquè tinc alguns en anglès i això m'ha salvat de ser bannejat vilment del adsense en general.

Total, l'adsense no es per fer-se ric, la veritat, però per pàgines grans i voluntaristes com relatsencatala.com, per exemple, creiem que pot ser una via de finançament molt vàlida.

20070510

Caiguda del twitter

El primer dia que faig servir el twitter i ja esta caigut.



Sabia que tenia mala fama, però com a mínim son cachondos ...

20070420

How to beat Desktop Tower Defense

Since last week I've been highly addicted to "Desktop Tower Defense", the start of the addiction was the post Desktop Tower Defense Considered Harmful of Jeremy Zawodny (good reference to 95's paper of Dijkstra Go To Statement Considered Harmful).


Anyway, I've been three or so days really obsessed, one day without sleep (literally).

I've decided to take my usual approach to addictive games... Finish them !!!



In the image you can see the powerful towers in the center of the battle field, thats the main trick to finish the game (click the image to make it bigger)

Until my discovery of the power of the last level of upgrade of the Squid Tower and the Pellet Tower the levels above 40 in the normal mode were like hell, but then I've discovered the Snipper Tower and the Thypoon Tower and seen the ligth.

My 5 tricks to finish "Desktop Tower Defense" this game are the following:

1. Create a maze-like structures with Pellet Towers (the cheapest ones)
2. It's better to upgrade only the central Towers (they have long range and can reach the start easily)
3. Save all your money to upgrade the central Towers
4. Sell some level 1 Pellet Towers to put Squirt Towers and take them to the final upgrade Thypoon Towers (they are better for the flying creeps
5. Use the "U" key to build upgrades on the selected tower, it's really better than going to and from the upgrade button all the time.

digg story

20070419

Gol de Messi vs. Gol de Maradona

Aquí podeu veure el gol de Maradona l'any 1986 contra Anglaterra comparat amb el de Messi contra el Getafe aquest any 2007.



20070331

Plagi de chupachups ?

No estic segur, pero la línea de baix de l'anunci de chupachups, "chupatube, the pleasure of sucking" (el de la noia que va a l'autobus) es gairebe igual que el de la canço de Gorillaz, Feel Good Inc.

Crec que canvien dues notes, prou per evitar el plagi descarat ?

Aquí el video de Gorillaz, l'altre no l'he trobat.



Que en penseu vosaltres ?

20070323

MEO, Meneame Engine Optimization

La nueva práctica dentro del mercado de la promoción de páginas web, no está en optimizarlas para los buscadores (SEO), sino en hacer noticias atractivas para las redes de noticias sociales que dirijan tráfico hacia la web del cliente (MEO).

En España, Meneame.net es líder indiscutible del mercado de las noticias sociales, si quieres saber más sobre el complejo negocio del MEO, debes seguir leyendo. En inglés el líder es digg, con lo que tendríamos el negocio del DEO, pero convendreis conmigo en que el nombre no mola tanto como el de MEO...

Las 10 reglas del buen MEO:

1. Noticias positivas sobre, creative commons, Meneame, software libre, Richard Stallman, Linus Torvalds, David Bravo, ajax, ruby on rails, Firefox, ubuntu (sobretodo beryl) etc. casi siempre serán bien recibidas

2. Noticias negativas sobre, SGAE, Bill Gates, Microsoft, Ramoncín, Internet Explorer, Fresqui, el canon, también tienen gran aceptación

3. Conoce a tu público: los karma whores (o putas del karma), son personajes que promocionan o hunden tu "wannabe-noticia" a la portada o a la miseria, respectivamente.
Existen dos tipos de karma whores, los simpáticos y los antipáticos. Los simpáticos, intentan subir su karma votando noticias pendientes, no importa ni siquiera el titular, sino que tenga bastantes votos ya y por tanto que su probabilidad de salir en portada sea alta, en cambio los karma whores antipáticos, buscan noticias con al menos un voto negativo, y le meten otro, con alguna excusa como "cansino" o "irrelevante" que tampoco necesita mucha justificación (además de ser anónimo), al llegar al warning de 4 votos negativos, ya te aseguras que la noticia no saldrá en portada, reportando al karma-whore-antipático su subida de karma correspondiente.

4. "Efecto bola de nieve" o "spike the vote", el buen MEO, tiene una buena lista de contactos (con diferentes IPs) normalmente disponibles a traves de mensajería instantánea, al introducir una nueva noticia pendiente, inmediatamente, se debe enviar a todos los contactos un mensaje para que voten la noticia lo más rápido posible, provocando que esta sea una buena candidata para los karma-whores-simpaticos, con lo que el efecto bola de nieve esta servido !

5. Sé humilde, el buen MEO debe asumir que fracasará en la mayoría de sus noticias, pero dentro de lo que cabe, conseguirá un buen número de accesos incluso sin llegar a la portada.

6. No discutas, el buen MEO, no quiere ser tachado de TROLL ni TALIBAN, así que simplemente no buscará explicación a clasificaciones de "irrelevante" o "cansino", si intenta exigir explicaciones o rebotarse con estos votos negativos (normales por la dinamica de karma-whores-antipáticos), sólo recibirá, más votos negativos y que los administradores se queden con tu cara (esto es tu IP y usuario)

7. El MEO debe asumir que como en cualquier comunidad hay un grado alto de endogamia y que existen grupos de poder que utilizan su propio código de conducta, jerga, etc. (nunca hablar de MAFIAS, bajo riesgo de ser tachado de LLORICA)

8. Es importante que el MEO se mimetize dentro del grupo de poder en la medida de lo posible. Es como un agent-provocateur dentro del grupo, entra en páginas como hoygan.php y tiene amiguetes dentro de los líderes de la comunidad. La regla sería: mejor pasarse de pelota y guardarse las críticas para sí. Créate una personalidad on-line, si puede ser de estudiante de informática que tiene mucho tiempo libre, mejor que mejor.

9. Conoce los mandamientos y la jerga del Cabal, la secta de los administradores de meneame, de hecho para ellos es una subcultura, mandamientos como "recordad, hay que censurar toda crítica al menéame, para eso están los votos negativos", "no eres un friki, eres un tío demasiado raro para ser friki", "el autobombo es spam sólo si es de un desconocido", podeis encontrar una lista completa mas abajo o en cabal.php del codigo fuente de meneame. Son frases en plan coña para hacer un "jiji-jaja", pero no esta de más conocerlas y tenerlas en el libro de cabecera del buen MEO :)

10. Este post es un ejemplo clarísimo de noticia que sera clasificada de "spam", "cansina", "irrelevante", etc.

Anexo, las frases del cabal:

"recordad, hay que censurar toda crítica al menéame, para eso están los votos negativos"
"no eres un friki, eres un tio demasiado raro para ser friki"
"los que cumplan con su misión purificadora recibirán karma y buenas galletas"
"el autobombo es spam sólo si es de un desconocido"
"los hombres puros sólo aman menéarsela"
"el mundo quiere destruirnos porque saben de nuestro poder, resistid, no visitéis otros webs de pecadores"
"el karma te llevará a la redención, para obtener karma debes proteger el mensaje del cabal"
"si un seguidor de nuestra causa envía una noticia vótala positivo independientemente de su contenido"
"todo envío de un desconocido es sospechoso, ante la duda votad negativo"
"si quieres tu galletas y gallinfantes, vota de acuerdo a los deseos del señor"
"recuerda, los que critican al menéame son unos trolls, vota negativo, tú tienes el poder"
"se debe evitar a toda costa que se publique una noticia negativa para el menéame"
"el mundo quiere eliminarnos, no uses Google ni Technorati, usa el buscador del menéame, allí está todo lo que necesitas saber"
"nuestra misión es destruir a todos los demás web sociales, recuerda, se lo merecen"
"sólo puede haber una verdad, las publicadas del menéame"
"como excepción y sólo en misión puedes visitar http://technorati.com/search/meneame pero recuerda debes trollear a todos los que critiquen a nuestra causa"
"si sientes que tu voluntad flaquea, visita http://mnm.uib.es/gallir/"
"gallir es un buen talibán, ámalo y comparte tu hombre o mujer con él, siempre hará un sacrificio"
"si llegas a tener 20 de karma es que has cumplido la misión, pero no debes relajarte ni un día"
"el diablo está en todos los Web 2.0, no te dejes seducir"
"los colores azul y verde son los signos del demonio, huye de ellos"
"el espagueti es nuestro señor, y el elefante es su hijo"
"cada chachi es un regalo, disfrútalo, pero no lo compartas con los enemigos"
"la cola de descartadas es el purgatorio de los pecadores que no hacen caso de nuestra voz"
"entrega tu donativo al señor en la cuenta 0118 999 881 999 119 725... 3"
"si tienes dudas de la orientación del voto para una noticia, te hemos preparado las 'recomendadas', haz caso de ellas"
"la perfección existe, el menéame existe, ergo el menéame es perfecto, quod erat demonstrandum"
"el color naranja es el símbolo de la redención y paz espiritual"
"Deus ex machina"
"los gallinfantes son un regalo del señor, no los maldigas ni nombres en vano"
"nuestro sistema es perfecto, el mundo es imperfecto"
"desconfía de las llamadas al pecado disfrazadas de reflexiones, la única reflexión válida es la del cabal"
"no desconfíes de los que tienen el karma alto, adóralos y sigue su ejemplo de sacrificio por nuestra noble causa"
"menéame no es un sitio Web 2.0, es la representación de la perfección del señor al alcance los humanos, es Perfección 2.0"
"nunca os abandonaré, renaceré de los backups"
"el éxito del menéame tiene a los grandes fósiles completamente descolocados", lo dijo Borjamari, todos sus pecados están perdonados"
"la lucha es dura, la recompensa es el karma"
"todos los que maldicen a nuestros dioses merecen ir a la cola de descartados"
"el Cabal es tu guía, el elefante tu compañía, el meneo negativo tu arma, los trolls tus enemigos, usa el arma"
"tú no eres un borrego, eres una oveja del señor"
"existen muchos siervos, pero tú y tus hermanos sóis los auténticos"
"http://meneame.net/story.php?id=14059, si has votado negativo tendrás que menear 12 veces en nombre del cabal"
"Neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit."
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Fusce pulvinar tempus est. Donec volutpat elit. Sed pretium condimentum est..."
"a quien tu se la menees, ese te la meneará a ti"
"no menees para otro lo que no querrías menear para tí"
"no hagas dobles sentidos con la palabra menear o la ira del Cabal caerá sobre tí"
"Cabalística es la ciencia del meneo supremo, estúdiala"
"a cada troll le llega su jotape"
"si tienes una queja contra el meneame, no lo digas fuera del fisgon (y pide perdón luego). si tienes alabanzas, publicalas en tu blog"
"la frecuencia se mide en hercios y el karma en meneos"
"ad-free es el símbolo del pecado oculto, 2 lame 4 ads es el de la pureza"
"Borjamari es nuestro Judas, mi hijo pródigo descarriado"
"el Cabal y sus diez apóstoles, adórales: http://photos1.blogger.com/blogger/7980/2144/1600/secta.jpg"
"el hombre es esclavo de lo que menea, dueño de lo que publica y temeroso de lo que descarta"
"el demonio dice "cuando veas tus visitas bajar, al menéame has de criticar"
"llego la hora que menees un poco, el cabal siempre te escucha"

20070211

Software de simulació espectacular

Vist a visuarios.com

20070128

Com descarregar els videos de la lliga del mundo i pujar-los al youtube



La gent de "El Mundo" i de "El Pais" han arribat a un acord amb "Audiovisual Sport" per penjar els videos de la lliga a les webs de les seves edicions electroniques.

elpais.com encara ha ocultat una mica el video, pero elmundo.es ha possat el flv molt accesible i es facilment baixable.

Nomes cal fer un "Ver codigo fuente" de la pagina del video (per exemple aquesta)

Busquem la part de la crida al flash:


var Parametros = "?nombreArchivo=/cr4ip/ES/videos/futbol/lfp/2006-2007/20/vil_rma/index.flv&fotograma=/elmundo/videos/futbol/lfp/2006-2007/20/vil_rma/index_0.jpg&anchoVideo=384&altoVideo=288" + nuevos_parametros; // Parametros que se le pasan al swf
if ( typeof(JSIncludePubli) != "undefined")
{
EscribeReproductorFlash(ArchivoFlash, Parametros, Ancho, Alto);
}

Nomes cal agafar l'adreça de ?nombreArchivo=X.flv i afegir-li davant

http://estaticos.elmundo.es

Aixi, en aquest cas la url del flv seria algo aixi com http://estaticos.elmundo.es/cr4ip/ES/videos/futbol/lfp/2006-2007/20/vil_rma/index.flv


Aqui ja podem provar el video amb algun software de visualitzacio de FLVs (com el FLV Player)

Despres nomes cal agafar un software de traduccio de FLV a AVI com el SUPER

Transformar el video i ja es pot penjar tranquilament de youtube.

Evidentment, no ho fare, i aquest tutorial no preten que ningu ho faci i violi els SAGRATS drets d'autor de AudioVisualSport

:)

20070122

Bug in animateClass jquery extension

If you have tried to use the excellent animateClass extension to jquery maybe you have found that doesn't work in IE.

For example this sample code changes dynamically a h1 element from class "inicial" to class "final" producing a nice transition animation when you enter the page.


<script type="text/javascript">
$(document).ready(function()
{
$('#titolseccio').animateClass('final', 500);
});
</script>


With this release of animateClass (January 2007) this example only works in some browsers (particularly Firefox, the most popular in the developers community), but fails in Internet Explorer 6 and 7 (shamefully the most broadly used by the rest of the mortals (including customers))

You can solve this particular problem patching the animateClass.js

You have to download the uncompressed version of animateClass.js and look for a line like this:

if( typeof newStyle[n] != "function" && newStyle[n] /* No functions and null properties



and add this two conditions:

&& typeof newStyle[n] != "boolean" && typeof newStyle[n] != "number"


Resulting in this line:

if( typeof newStyle[n] != "function" && typeof newStyle[n] != "boolean" && typeof newStyle[n] != "number" && newStyle[n] /* No functions and null properties */


Now you can save your patched version of animateClass.js and reload your html page in Explorer (remember to Shift+Reload to avoid cached .js confusions)

The explanation of the problem is that javascript IE doesn't allow you to use string functions (like replace) on booleans and numbers, causing an unhandled exception.

Watch Out, this is not a generic patch, I'll warn the animateClass developer to patch it properly. For example, with this patch, you will not be able to animate any number CSS value (in the example the animation is from "20px" to "40px" the px makes it a string value, not a number).

20070115

Post de resum del 2006

Amb una mica de retard ...

Gadgets of the year (comprats o regalats):
La Fonera
iPOD Shuffle
Portàtil ACER
Guitarra Red Octane (Guitar Hero)

Samarretes del any:
La vida son Contrarios
Bug Fixed
Red or Dead de Divinas Palabras
Ovolution


Friky coses guays del 2006:

JQuery
Ruby on Rails
CakePHP
OpenLaszlo

Coses que he aprés al 2005:
API Rest del YOUTube
JQuery
Prototype + Scriptaculous
CakePHP

Jocs als que m'he viciat aquest any:
WarHammer 40.000, Dawn of War al PC
Guitar Hero I i II a la PSP

Nous grups del 2006 que m'han agradat:
Girls in Hawaii
Be Brave Benjamin
Ghost to Falco

Grups que he descobert aquest any:
The Spinto Band
Artick Monkeys
Josh Ritter


Millor concert al que he anat:
Pixies al FIB 2006
(seguit d'aprop de Belle and Sebastian i Happy Mondays al Primavera Sound)

Millors pelis que he vist:
Salvador
Ficció

Llibres que he llegit i m'han agradat:
Búsqueda - John Battelle
Sistemas Emergentes - Steven Johnson
Pere Calders - Tots els contes
Todd Solondz, en los suburbios de la felicidad - Jordi Costa
Amos del Mundo - Juan Carlos Castillón


Comics:
V de Vendetta
Watchmen
Persépolis
Lenore

Series a les que m'he enganxat (per ordre d'adicció):
Prison Break
Six Feet Under
Scrubs
My Name is Earl
IT Crowd
Little Britain
Lost
CSI Las Vegas

Sortides al Extranjer:
Costa Rica
Benicassim i Castelló
Cardiff

Millors Hotels als que he anat:
Pachira Lodge, Tortuguero, Costa Rica
Abba Castellón
Park Plaza Hotel, Cardiff


On he menjat millor:

Els Pescadors
Celler de Can Recasens (Poblenou)
Abba Castellón
El castell de Can Gimenelles

20070112

How to look for long running pages in the Apache Logs using awk

In this tutorial we will learn how to look for pages, that takes 3 or more seconds to be served by Apache.

Usually the slow pages will be some sort of dynamic ones (PHPs, ASPs, Servlets or JSPs) because the static html pages take very short time to be served.


This procedure can help you in find some bottlenecks in your dynamic web application.


First step, change your Apache configuration



Locate your httpd.conf usually located in the $APACHE_HOME/conf directory

Edit the file (vi powa) and change the format of the Log File, adding a %T at the end.

Example:
from:
LogFormat "%h %l %u %t \"%r\" %>s %b" common
to:
LogFormat "%h %l %u %t \"%r\" %>s %b %T" common

Restart your apache server



go to $APACHE_HOME/bin ./apachectl stop and ./apachectl start

Now, if you locate the log file and take a look on the output (tail -f access_log) you can see the last column is the time taken in seconds to serve the page.

Example:

555.254.999.71 - omatech [12/Jan/2007:12:12:47 +0100] "GET /omatech/rulez/pk_microcalls.view_tralari_tralara?p_user_logged_id=1&p_load_id=07 HTTP/1.1" 200 3713814 4
555.254.999.71 - omatech [12/Jan/2007:12:38:35 +0100] "GET /omatech/rulez/pk_microcalls.view_ekipoja?p_user_id=1&p_type=C&p_cust=739 HTTP/1.1" 200 73793 5


In the above example, the first request have taken 4 seconds, and the second 5 seconds.

Extract the long duration requests with awk



This is the tricky one, you must use awk to extract the requests that takes more than 3 seconds, this step is useful because you eventually will have lots and lots of requests that take 0 seconds.


awk '/[^0-2]$/ {print $0}' access_log



This line uses awk to parse the file and extract the lines that DO NOT ends with 0, 1, or 2.


The [^] is for negation, the 0-2 is the range, and the $ stands for "at the end of the line"

I hope it will be useful