El Zen de Python i el mestre Yoda.

Confesso que el Python m’agrada molt. L’he fet servir en posts del bloc més d’un cop i m’ho vaig passar molt bé al curs de Python de Coursera. repetixo, m’agrada molt.

Doncs bé, fa molt temps vaig llegir una història curta, es tractava d’una escena de la pel·lícula “L’imperi contraataca” però amb els textos canviats. Luke Skywalker carrega amb Yoda a l’esquena tot entrenant-se però no en els camis de la força, si no en els camins de la programació.

EL Python és el llenguatge dels jedis, i el Perl, dels siths. El diàleg es genial.

Voltant per la web de Pyhton he trobat la historia a l’apartat Python humor, on també s’hi poden trobar d’altres històries i bromes sobre Python.

Pel seu interès, reprodueixo un parell de texts: el primer, “el Zen de Python” de Tim Peters, Val a dir que aquest es pot llegir a qualsevol interpret de python, només cal fer import this. És un ou de pasqua. O potser no. Doncs, en veritat us dic, que paraules poderoses són aquestes.

albert@athena:~$ python
Python 2.7.3 (default, Jan  2 2013, 13:56:14) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>> 

I el segon text, és “Python vs. Perl, segons Yoda”

Subject: Python versus Perl: A humorous look
From: larry (funkster@midwinter.com)
Date: 10 Jul 1999 01:45:07 -0700

This has been percolating in the back of my mind for a while.
It's a scene from _The Empire Strikes Back_ reinterpreted to serve
a valuable moral lesson for aspiring programmers.

--

EXTERIOR: DAGOBAH -- DAY
           With Yoda strapped to his back, Luke climbs up one of
        the many thick vines that grow in the swamp until he
        reaches the Dagobah statistics lab. Panting heavily, he
        continues his exercises -- grepping, installing new
        packages, logging in as root, and writing replacements for
        two-year-old shell scripts in Python.

YODA: Code!  Yes.  A programmer's strength flows from code
      maintainability.  But beware of Perl.  Terse syntax... more
      than one way to do it...  default variables.  The dark side
      of code maintainability are they.  Easily they flow, quick
      to join you when code you write.  If once you start down the
      dark path, forever will it dominate your destiny, consume
      you it will.

LUKE: Is Perl better than Python?

YODA: No... no... no.  Quicker, easier, more seductive.

LUKE: But how will I know why Python is better than Perl?

YODA: You will know.  When your code you try to read six months
      from now.

May the force be with you!

url jdbc d’oracle per SID o per Service Name

Apunt ràpid de java i Oracle. La forma de fer servir bases de dades relacionals a Java és amb JDBC. LA connexió es basa en drivers que, depenent del protocol d’accés a la base de dades, són de diferents tipus.

Per accedir a bases de dades Oracle es recomana fer servir els drivers JDBC de tipus IV, que són drivers java pur.

Ara mateix estic involucrat amb el manteniment d’una aplicació que fa servir una BD java i en la migració d’aquesta aplicació d’un servidor Weblogic 8.1 a un JBoss 4.0 (sí, ja se, aquesta tecnologia és antiga!).

Java ja complert la seva promesa de “write once run anywhere” i la migració ha estat directa: el war s’ha desplegat sense canvis. Lògicament ha calgut modificar alguns fitxers de configuració per apuntar a nous paths.

1. Ha calgut posar el jar amb el driver d’oracle a la carpeta server/default/lib .
2. Els datasources a JBoss es despleguen copiant un fitxer xml amb sufix -ds.xml a la carpeta de deploy.

Les connexions JDBC a base de dades prenen la forma d’URL. I vet aquí el que cal tenir en compte: A Oracle la URL JDBC pren formes diferents si s’accedeix per SID, o si s’accedeix per Service Name. Haurem de saber de quina forma cal accedir. És una informació que ens haurà de proporcionar el DBA. En general , el SID és el nom únic (l’identificador) de la base de dades; i el Service name, ve a ser el nom públic amb el que la Base de dades està registrada al listener. SID i Service Name poden coincidir, o no.

La forma de la URL per sid és: jdbc:oracle:thin:@host:port:SID
Un exemple de fitxer de datasource de JBoss amb URL JDBC d’Oracle accedint per SID

<?xml version="1.0" encoding="ISO-8859-1"?>
<datasources>
   <local-tx-datasource>
      <!-- jndi name -->
      <jndi-name>ElMeuDataSource</jndi-name>
	  
	  <!-- url -->
      <connection-url>jdbc:oracle:thin:@host:port:SID</connection-url>

      <!-- driver class -->
      <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>

      <!-- login i password -->
      <user-name>usuari</user-name>
      <password>password</password>
   </local-tx-datasource>
</datasources>

La forma de la URL per Service Name és: jdbc:oracle:thin:@//host:port/SERVICE_NAME

La diferència es troba a ‘//’ entre @ i al host; i el separador entre port i SID (‘:’), o entre port i Service Name (‘/’).
Un exemple de fitxer de datasource de JBoss amb URL JDBC d’Oracle accedint per Service Name

<?xml version="1.0" encoding="ISO-8859-1"?>
<datasources>
   <local-tx-datasource>
      <!-- jndi name -->
      <jndi-name>ElMeuDataSource</jndi-name>
	  
	  <!-- url -->
      <connection-url>jdbc:oracle:thin:@//host:port/SERVICE_NAME</connection-url>

      <!-- driver class -->
      <driver-class>oracle.jdbc.driver.OracleDriver</driver-class>

      <!-- login i password -->
      <user-name>usuari</user-name>
      <password>password</password>
   </local-tx-datasource>
</datasources>

Un últim detall, a Weblogic feia servir el datasource directament per nom ‘ElMeuDataSource’; a JBoss ha estat necessari afegir el prefix java: al nom del datasource per a utilitzar-lo. És dir: ‘java:ElMeuDataSource’

Truc: una transició entre imatges amb jQuery

Un amic de la casa, Scmute, que és l’impulsor del netlabel i l’associació Tecnonucleo i webmaster dels respectius llocs web, aprofitant que està remodelant les pàgines, em passa aquest truc per a fer transicions entre dues imatges.

És un exemple del localitzador  de jquery  i de com es poden tocar les propietats css dels elements directament. Com a detall, indicar que la propietat d’opacitat es declara dos cops, una per a navegadors IE i l’altre per a la resta. Però després es referencien de forma única des del javascript . El jQuery n’encapsula l’accés.

Vet aquí el codi:

<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
        <script src="jquery-1.8.2.js"></script>
        <style>
            .p{
                height:198px;
                width:198px;
                cursor:pointer;
                opacity: 1;
            }
            .c{
                height:198px;
                width:198px;
                cursor:pointer;
                filter: alpha(opacity=0);
                opacity: 0;
            }
        </style>
    </head>
    <body>
        <div class="p" style="background-image: url('imatge1.jpg')"/>
        <div class="c" style="background-image: url('imatge2.jpg')"/>
        <script>
            $(".c").hover(
                function(){
                    $(this).stop().animate({"opacity":0.9});
                },
                function(){
                    $(this).stop().animate({"opacity":0});
            });
        </script>
    </body>
</html>

Si voleu veure el truc en acció, mireu aquest enllaç.

Com afegir un captcha amb PHP i Securimage

Com fer un captcha amb PHP?

Una de les formes habituals de protegir formularis web de l’acció de robots o programes que fan peticions automàtiques és afegir un captcha.

Els captcha són aquestes paraules generades aleatòriament i que es mostren amb les lletres deformades, ratllades, sobre fons degradats o de trames… de forma que no poden ser reconegudes per programes d’OCR, però sí per operadors humans. Aleshores, per validar el formulari web protegit per un captcha, l’operador humà ha d’encertar la paraula o paraules que “oculta”.

Es tracta d’una prova que permet garantir amb una certesa prou important (si més no, per ara) que qui envia el formulari és una persona i no un robot.

No cal inventar la roda. Per afegir un captcha a les nostres aplicacions web n’hi ha prou amb incorporar alguna de les llibreries que es poden trobar per Internet. Per descomptat, trobarem llibreries de codi obert, i en una varietat de llenguatges.

Amb PHP hem provat aquesta: Securimage. Es pot descarregar de la seva pàgina de download.

A dia d’avui podem descarregar la versió 3. També podem descarregar una pàgina de proves per a determinar si la nostra instal·lació té les versions adequades de PHP i llibreries gràfiques per a suportar-la.

A la web de Securimage (http://www.phpcaptcha.org/) trobarem documentació, FAQ, demos…

A continuació faré un petit exercici per a demostrar com afegir un captcha a una aplicació web.

El plantejament és el següent:

  • Faré un formulari web amb els camps nom, email, i captcha
  • El formulari va a una pàgina de resposta que valida el captcha. Si la validació és correcta, ens donarà un missatge de benvinguda; si la validació no és correcta, ens informarà de captcha erroni.

És dir, dues pàgines php:

  • El formulari web.
  • la pàgina de resposta.

A la QuickStart Guide ens explica com hauran de ser aquestes pàgines.

Estic desenvolupant en un entorn local amb Xampp. He creat una carpeta captcha a l’htdocs. Dins aquesta carpeta he descomprimit la llibreria securimage. Ara tinc, dins de la carpeta captcha, una carpeta securimage amb la llibreria securimage.php i la resta de fitxers auxiliars.

A la carpeta captcha poso la pàgina de formulari. Fixem-nos que és una pàgina php senzilla en la que només hi ha la invocació a la sessió php com a únic codi de servidor. La resta és un formulari web senzill.

El captcha es genera invocant securimage_show.php.al src de l’etiqueta img.

Securimage_show.php amaga una seqüència similar a aquesta:

    require_once 'securimage.php';
    $image = new Securimage();
    $image->show();

El camp d’entrada corresponent al text del captcha és un input type text normal.

En el cas que el text del captcha sigui il·legible, amb el javascript de l’enllaç es torna a invocar securimage_show.php per a generar-ne un de nou. Fixem-nos en l’ús de Math.random() per a evitar problemes de caché..

Vet aquí el codi

<?php session_start(); ?>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<title>Pàgina de prova del formulari</title>
</head>
<body>
<form action="prova-resposta.php" method="post">
Nom: <input type="text" name="sNom" maxlength="20" /><br />
Email: <input type="text" name="sEmail" maxlength="40" /><br />

<!-- el captcha, propiament dit -->
Captcha: <br />
<img id="captcha" src="securimage/securimage_show.php" alt="CAPTCHA Image" /><br />

<!-- el camp d'entrada -->
<input type="text" name="sCaptcha" size="10" maxlength="6" />

<!-- Per si la imatge del captcha no s'entén, es permet la possibilitat de generar-ne un altre-->
<a href="#"
onclick="document.getElementById('captcha').src = 'securimage/securimage_show.php?' + Math.random(); return false">
[ genera un nou captcha ]</a>
<br />
<input type="submit" value="envia"/>
</form>
</body>
</html>

I ara el codi del prova-resposta.php. Aquesta pàgina tindrà com esquelet la següent seqüència de codi:

    require_once 'securimage.php';
    $image = new Securimage();

    if ($image->check($_POST['sCaptcha']) == true) {
      echo "Correcte!";
    } else {
      echo "Codi erroni!";
}

Vet aquí el codi:


<?php session_start(); ?>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<title>Pàgina de resposta del formulari</title>
</head>
<body>
<?php
# carreguem la llibreria
include_once 'securimage/securimage.php';

#instanciem l'objecte de captcha
$securimage = new Securimage();

if ($securimage->check($_POST['sCaptcha']) == true) {
?>
Validació correcte!<br />
paràmetres llegits: <br />
sNom: <?php echo($_POST['sNom']) ?> <br />
sEmail: <?php echo($_POST['sEmail']) ?> <br />
<?php
} else {
?>
Validació incorrecte!<br />
<a href="prova-form.php">Torna a provar</a><br />
<?php
}
?>
</body>
</html>

I un exemple d’execució

i la resposta

Com evitar la redirecció a "blogger.com.es"

Aquest matí m’he trobat que Google ja havia aplicat la redirecció automàtica dels blogs a Blogger.com a blogger.com.es.

“.com” és el domini internacional per excel·lència. Posats a triar un domini local, en el cas del bloc d'”Apunts de tecnologia” que des del principi ha fet servir el català i que és militant en l’ús de la nostra llengua, no hi ha cap dubte que el més escaient seria el domini “.cat”.

Tanmateix, i mentre no tingui el .cat, com puc recuperar el domini .com?

Doncs bé, aquest canvi de Google ha provocat la reacció immediata de la comunitat blocaire catalana que ja han publicat diferents mètodes per a evitar aquesta redirecció. Des de l’opció més radical, que seria migrar a WordPress, fins a d’altres que mantenen el bloc a Blogspot.

Apunts de Tecnologia” ha aplicat aquest, que amaga el “.es”, publicat per  Xavier Caballé al seu bloc “L’Home Dibuixat”.

Enganxat directament des del bloc “L’Home Dibuixat”:
  • Aneu a l’edició de la plantilla del bloc:

Edició de la plantilla HTMLEdició de la plantilla HTML
i escolliu l’opció “Modifica l’HTML”. Es mostrarà un avís:
Avís de la modificació de la plantillaAvís de la modificació de la plantilla
Feu clic a “Continua” i a l’editor HTML afegiu el codi que s’indica més avall:
Inserir el codi HTML per evitar la redireccióInserir el codi HTML per evitar la redirecció

  • Enganxeu aquest codi immediatament per sota de la marca <head>

<script type=“text/javascript”>if ((window.location.href.toString().indexOf(‘.com/’))==’-1′){window.location.href = window.location.href.toString().replace(‘.blogspot.com.es/’,’.blogspot.com/ncr/’);}</script>

Moltes gràcies, Xavi!

Retardador de subtítols SubRip (again). BeanShell version.

El mateix retardador de subtítols del post anterior, ara fet amb BeanShell.

Suposant que guardo l’script al fitxer delayer.bsh i que tinc el fitxer prova.srt del post anterior, aleshores puc retardar l’aparició dels subtítols amb la següent línia de comandes:

./delayer.bsh prova.srt output.srt 10000

Vet aquí el codi:

#!/usr/bin/bsh
 

import java.text.DateFormat;
import java.text.SimpleDateFormat;

// obté els arguments
args = this.interpreter.get(“bsh.args”);

// verifica que té 3 arguments
if (args.length != 3 ) {
    sUsage = “Usage:\tdelayer filein.srt fileout.srt delay” +
             “\n\texample 1: delayer filein.srt fileout.srt 10000 –> delays 10 seconds” +
             “\n\texample 2: delayer filein.srt fileout.srt -10000 –> advances 10 seconds”;

    print(“incorrect number of arguments”);
    print(sUsage);
    System.exit(1);
}

// calcula el delta
lDelta = Long.parseLong(args[2]);

// prepara el SimpleDateFormat
sdf = new SimpleDateFormat(“HH:mm:ss,SSS”);

// obre els fitxers args[0] per a lectura i args[1] per a escriptura
fFileIn = new FileReader(args[0]);
fFileOut = new FileWriter(args[1]);
brFileIn = new BufferedReader(fFileIn);
brFileOut = new BufferedWriter(fFileOut);

while((sLine = brFileIn.readLine()) != null) {
    sTokens= sLine.split(“–>”);   // mètode split() milor que StringTokenizer des de JDK1.4.
    if (sTokens.length == 2) {
    // si té dos elements, és la línia de temps

    // els “pela”
    sTempsInici = sTokens[0].trim();
    sTempsFi = sTokens[1].trim();

    // els converteix a Date
    dTempsInici = sdf.parse(sTempsInici);
    dTempsFi = sdf.parse(sTempsFi);

    // Els suma el retard
    dTempsIniciDelayed = new Date(dTempsInici.getTime() + lDelta);
    dTempsFiDelayed = new Date(dTempsFi.getTime() + lDelta);

    // converteix els Date a String amb el mateix SimpleDateFormat
    sTempsIniciDelayed = sdf.format(dTempsIniciDelayed);
    sTempsFiDelayed = sdf.format(dTempsFiDelayed);

    // Munta la línia
    sLine = sTempsIniciDelayed + ” –> ” + sTempsFiDelayed;
    }

    // escriu la línia
    brFileOut.write(sLine);
    // i salta de línia
    brFileOut.newLine();
}

// tanca fitxers i buffered readers / writers
brFileOut.close();
brFileIn.close();
fFileIn.close();
fFileOut.close();

// i acaba aquí

Molt poques coses a dir. Si de cas destacar que:

No he declarat els tipus de cap variable.

No ha calgut importar les classes de java.io ni java.util.En canvi sí les de java.text

Us de

// obté els arguments
args = this.interpreter.get(“bsh.args”);

per obtenir els arguments de la línia de comandes.

Evidentment, la versió amb Python i optparse era més potent funcionalment pel que fa al tractament dels arguments d’entrada. Ara bé, a la simplicitat en aquest cas juga a favor i fa que l’argument de retard negatiu es tracti de forma més natural que amb la solució Python.

Us del format HH:mm:ss,MMM (hores de  0 a 23:minuts:segons,milisegons) al SimpleDateFormat, tant per a parsejar strings com per a formatar dates.

I finalment, l’us d’Split, en comptes del clàssic StringTokenizer per a obtenir els temps d’inici i final de presentació dels subtítols.

Què és més eficient? Python o BeanShell? Per a aquest cas, ho deixo en empat. Per mi ha estat més fàcil BeanShell que Python, però crec que això respon al fet que estic molt més familiaritzat amb Java.

El proper pas podria ser escriure el mateix script en Groovy. Sospito que només caldrà tocar el pas d’arguments i poca cosa més.

El calendari en mode text de l’Ubuntu Linux

Hi han molts bons programes d’agenda i de calendari. Amb Linux (Ubuntu) n’hi ha un en mode text que ja ve de fàbrica: Es tracta del programa calendar.

calendar és un altre dels molts petits programes que es poden trobar als sistemes UNIX que fan una cosa senzilla, que la fan bé, i que es poden ajuntar amb altres petits programes per a realitzar tasques útils per a l’usuari. La tradicional i efectiva filosofia UNIX, ni més ni menys.

N’hi ha prou amb crear el fitxer calendar a la carpeta .calendar i afegir-hi línies amb les dates que ens interessin amb el format data <tabulació> descripció de la data. Finalment, si afegeixo calendar al fitxer .bashrc sempre que obri una finestra de terminal em revisarà el calendari.

Una altre forma d’utilitzar aquest petit programa podria ser invocant-lo des d’una aplicació que fem servir de forma habitual, potser una macro d’OpenOffice.org/LibreOffice o des d’un menú de llançament d’aplicacions fet amb zenity.

El que ve a continuació és la traducció lliure de la pàgina del manual de calendar.

Us:

calendar [-ab] [-A num] [-B num] [-l num] [-w num] [-f fitxer_de_calendari] [-t [[[cc]aa][mm]]dd]

Descripció:

Aquesta utilitat busca al directori actual, o al directori especificat a la variable d’entorn CALENDAR_DIR, un fitxer amb el nom calendar i mostra les línies que comencen amb la data d’avui i demà. Els divendres es mostren els events de tot el cap de setmana.

Les opcions són:

-A num  Mostra els propers esdeveniments d’avui i dels propers num dies. Per defecte és un dia.

-a      Processa els fitxers “calendar” de tots els usuaris i els envia un corru amb els resultats a cadascun d’ells. requereix privilegis de súper-usuari.

-B num  Mostra els fets esdevinguts entre d’avui i els passats num dies.

-b      Força mode de càlcul especial de dates per als calendaris KOI8.

-l num  Mostra els propers esdeveniments d’avui i dels propers num dies. Per defecte és un dia.

-w num  Mostra els propers esdeveniments d’avui i dels propers dos dies, però només si avui és divendres. És dir, mostra els esdeveniments del cap de setmana.

-f fitxer_de_calendari    fa servir fitxer_de_calendari en comptes del fitxer per defecte calendar.

-t [[[cc]aa][mm]]dd    fa servir la data especificada per cc, centúria; aa, any; mm, mes; dd, dia; en comptes de la data d’avui.

Les línies poden començar amb mes i dia. Si estan ben definides les característiques locals del sistema es poden fer servir els noms dels mesos i els dies de la setmana.

Un asterisc (‘*’) vol dir cada mes.
Un dia sense mes vol dir aquell dia cada setmana
Un mes sense dia vol dir el primer dia d’aquell mes.
Dos números volen dir mes i dia.
les línies que comencen amb un caràcter de tabulació es refereixen a l’última data entrada, permetent d’aquesta forma línies d’especificacions múltiples per a una data
Els dies de la setmana poden  anar seguits de “-4” … “+5” (àlies last, first, second, third, fourth) per esdeveniments amb data variable del tipus “el darrer dilluns d’abril”.
El diumenge de pasqua és ‘Easter’ en anglès. Es pot posar un àlies fent Easter=àlies i fer servir l’àlies

Per conveni, les dates seguides d’un asterisc (‘*’) no són fixes, és dir, canvien d’any en any.

Les descripcions del dia inicien després del primer caràcter de tabulació de la línia. Si una línia no té caràcter de tabulació, no es mostra. Si el primer caràcter d’una línia és una tabulació aleshores es tracta de la continuació de la descripció prèvia.

El calendari és preprocessa amb el preprocessador de C, cpp, permetent la inclusió de fitxers compartits com poden ser, per exemple, les vacances de l’empresa, el calendari de reunions, o l’agenda de cursos.

Si el fitxer compartit no es referencia per una ubicació absoluta aleshores es mira primer al directori actual (o home) i després a /etc/calendar, i finalment a /usr/share/calendar.

Les línies buides o protegides amb comentaris amb la sintaxi de C son ignorades.

On busca el calendari?
calendar              fitxers al directori actual.
~/.calendar           directori ocult ubicat al directori de l’usuri.
~/.calendar/calendar  fitxers que fa servir si no hi un fitxer calendar al directori actual.
~/.calendar/nomail    si el fitxer nomail existeix, no s’envia el calendari del dia a aquel usuari (opció -a).

Els següents fitxers es poden trobar a /usr/share/calendar i contenen llistes d’efemèrides
calendar.all          fitxers calendar nacionals i internacionals.
calendar.birthday     dates de naixement i decés de personatges famosos.
calendar.christian    calendari cristià (però no està de més revisar-ne les dates).
calendar.computer     efemèrides rel·lacionades amb el món de la informàtica.
calendar.croatian     calendari croata.
calendar.discordian   el calendari de la discòrdia.
calendar.fictional    dates i efemèrides fantàstiques i de ficció .
calendar.french       calendari francès.
calendar.german       calendari alemany.
calendar.history      miscel·lània d’efemèrides.
calendar.holiday      altres festes.
calendar.judaic       calendari jueu.
calendar.music        dates del món del rock and roll.
calendar.openbsd      esdeveniments rel·lacionats amb el bsd.
calendar.pagan        festes paganes.
calendar.russian      calendari rus.
calendar.space        història de cursa espacial.
calendar.ushistory    esdeveniments històrics dels EUA.
calendar.usholiday    festes dels EUA.
calendar.world        esdeveniments mundials.

Exemple (\t és el caràcter de tabulació):

LANG=C
Easter=DiumengePasqua
#include <calendar.usholiday>
#include <calendar.birthday>

6/15\tJune 15 (Si és ambigu, es prem mes/dia).
Jun. 15\tJuny 15.
15 June\tJuny 15.
Thursday\tCada dijous.
June\tCada primer de juny.
15 *\tEl 16 de cada mes.

May Sun+2\tsegon diumenge de maig (Muttertag)
04/SunLast\túltim diumenge d’abril,
\tentra l’horari d’estiu a europa
Easter\tdiumenge de pasqua
DiumengePasqua\tdiumenge de pasqua (amb àlies)
Easter-2\tdivendres sant (2 dies abans de diumenge de pasqua)
DiumengePasqua\t-2\tdivendres sant(com abans, però amb àlies)
Paskha\tPasqua ortodoxa

Un altre exemple, més senzill:

#include <calendar.usholiday>
#include <calendar.russian>
#include <calendar.discordian>
#include <calendar.christian>
#include <calendar.computer>
#include <calendar.birthday>

07/31    últim dia de les vacances d’estiu 2011
08/01    Sant Tornem-Hi

El resultat avui és (30 de juliol):

Fer servir zenity per a construir scripts bash amb interfície gràfica

La creació d’scripts de shell és una tasca habitual en l’administració i explotació de sistemes Unix. En algunes ocasions pot ser que calgui la interacció amb l’usuari. Per exemple, la presentació de menús d’opcions o l’usuari ha de triar què vol fer.

A Linux Ubuntu hom pot trobar eines com el programa Dialog que permet crear elements de interfície gràfica com caixes de text, llistes, botons de sel·lecció… en mode de text. Dialog es feia servir, per exemple, en els instal·ladors de moltes distribucions.

Una opció alternativa és fer servir Zenity. Zenity és la re-escriptura de GDialog, que al seu torn era la versió GNOME de Dialog. Zenity proporciona una forma senzilla de crear interfícies gràfiques per a scripts.

Zenity es pot instal·lar des del Centre de Programari de l’Ubuntu, si cal.

Anem a fer alguns experiments amb aquesta eina. Primer de tot cal conéixer la versió que tenim instal·lada i les opcions.

La versió s’obté amb zenity –version. En el meu cas és la 2.30.

Les diferents opcions s’obtenen amb: zenity –help-all a la línia d’ordres i el resultat és:

Forma d’ús:
  zenity [OPCIÓ…]

Opcions d’ajuda:
  -h, –help                            Mostra les opcions d’ajuda
  –help-all                            Mostra totes les opcions d’ajuda
  –help-general                        Mostra les opcions generals
  –help-calendar                       Mostra les opcions del calendari
  –help-entry                          Mostra les opcions de l’entrada de text
  –help-error                          Mostra les opcions d’error
  –help-info                           Mostra les opcions d’informació
  –help-file-selection                 Mostra les opcions del selector de fitxers
  –help-list                           Mostra les opcions de llistes
  –help-notification                   Mostra les opcions de la icona de notificació
  –help-progress                       Mostra les opcions del progrés
  –help-question                       Mostra les opcions de preguntes
  –help-warning                        Mostra les opcions d’avisos
  –help-scale                          Mostra les opcions de l’escala
  –help-text-info                      Mostra les opcions de text informatiu
  –help-misc                           Mostra les opcions miscel·lànies
  –help-gtk                            Mostra les opcions del GTK+

General options
  –title=TÍTOL                         Estableix el títol del diàleg
  –window-icon=CAMÍ D’ICONA            Estableix la icona de la finestra
  –width=AMPLADA                       Estableix l’amplada
  –height=ALÇADA                       Estableix l’alçada
  –timeout=TEMPS D’ESPERA              Estableix el temps d’espera del diàleg (en segons)

Calendar options
  –text=TEXT                           Estableix el text del diàleg
  –day=DIA                             Estableix el dia del calendari
  –month=MES                           Estableix el mes del calendari
  –year=ANY                            Estableix l’any del calendari
  –date-format=PATRÓ                   Estableix el format de la data de tornada

Text entry options
  –text=TEXT                           Estableix el text del diàleg
  –entry-text=TEXT                     Estableix el text de l’entrada
  –hide-text                           Amaga el text de l’entrada

Error options
  –text=TEXT                           Estableix el text del diàleg
  –no-wrap                             No habilites l’ajustament del text

Info options
  –text=TEXT                           Estableix el text del diàleg
  –no-wrap                             No habilites l’ajustament del text

File selection options
  –filename=NOM DE FITXER              Estableix el nom del fitxer
  –multiple                            Permet la selecció de múltiples fitxers
  –directory                           Activa la selecció de només directoris
  –save                                Activa el mode d’estalvi
  –separator=SEPARADOR                 Estableix el caràcter de separació de la sortida
  –confirm-overwrite                   Confirmeu la selecció del fitxer si el nom del fitxer ja existeix
  –file-filter=PATRÓ 1 PATRÓ 2 …     Estableix un filtre per al nom de fitxer

List options
  –text=TEXT                           Estableix el text del diàleg
  –column=COLUMNA                      Estableix la capçalera de la columna
  –checklist                           Utilitza quadres de verificació per a la primera columna
  –radiolist                           Utilitza botons de grup per a la primera columna
  –separator=SEPARADOR                 Estableix el caràcter de separació de la sortida
  –multiple                            Permet la selecció de múltiples files
  –editable                            Permet canvis al text
  –print-column=NOMBRE                 Imprimeix una columna específica (el valor per defecte és 1. Es pot usar ‘ALL’ per a imprimir totes les columnes)
  –hide-column=NOMBRE                  Amaga una columna específica
  –hide-header                         Oculta les capçaleres de la columna

Notification icon options
  –text=TEXT                           Estableix el text de la notificació
  –listen                              Espera ordres de l’entrada estàndard

Progress options
  –text=TEXT                           Estableix el text del diàleg
  –percentage=PERCENTATGE              Estableix el percentatge inicial
  –pulsate                             Barra de progrés parpellejant
  –auto-close                          Tanca el diàleg quan s’arribi al 100%
  –auto-kill                           Mata el procés para si es prem el botó de cancel·lar

Question options
  –text=TEXT                           Estableix el text del diàleg
  –ok-label=TEXT                       Estableix l’etiqueta del botó D’acord
  –cancel-label=TEXT                   Estableix l’etiqueta del botó Cancel·la
  –no-wrap                             No habilites l’ajustament del text

Warning options
  –text=TEXT                           Estableix el text del diàleg
  –no-wrap                             No habilites l’ajustament del text

Scale options
  –text=TEXT                           Estableix el text del diàleg
  –value=VALOR                         Estableix un valor inicial
  –min-value=VALOR                     Estableix el valor mínim
  –max-value=VALOR                     Estableix el valor màxim
  –step=VALOR                          Estableix el valor dels augments
  –print-partial                       Imprimeix valors parcials
  –hide-value                          Amaga el valor

Text information options
  –filename=NOM DE FITXER              Obre un fitxer
  –editable                            Permet canvis al text

Miscellaneous options
  –about                               Quant a zenity
  –version                             Imprimeix la versió

Opcions del GTK+
  –class=CLASS                         Program class as used by the window manager
  –name=NAME                           Program name as used by the window manager
  –screen=SCREEN                       X screen to use
  –sync                                Make X calls synchronous
  –gtk-module=MODULES                  Load additional GTK+ modules
  –g-fatal-warnings                    Make all warnings fatal

Opcions de l’aplicació:
  –calendar                            Mostra el diàleg de calendari
  –entry                               Mostra el diàleg d’entrada de text
  –error                               Mostra el diàleg d’error
  –info                                Mostra el diàleg d’informació
  –file-selection                      Mostra el diàleg de selecció de fitxers
  –list                                Mostra el diàleg de llista
  –notification                        Mostra una notificació
  –progress                            Mostra el diàleg d’indicació de progrés
  –question                            Mostra el diàleg de pregunta
  –warning                             Mostra el diàleg d’avís
  –scale                               Mostra el diàleg d’escala
  –text-info                           Mostra el diàleg de text informatiu
  –display=DISPLAY                     X display to use

Anem a provar-los un per un:

Mostrar el diàleg de calendari:

zenity –calendar

Mostrar una caixa d’entrada de text

zenity –entry –text=”Entra un text de prova”

El següent script mostra com obtenir el text introduït

#!/bin/bash

textPregunta=”Text de la pregunta”
textPredet=”Text predeterminat a l’entrada”
textTitol=”Títol de la finestra”

resp=$(/usr/bin/zenity –entry –text=”$textPregunta” –entry-text=”$textPredet” –title=”$textTitol” –width=400 –height=200)

echo “la meva resposta ha estat: $resp”

Mostrar una finestra de missatge d’error

zenity –error –text=”Descripció de l’error”

Mostrar el diàleg de sel·lecció de fitxers

zenity –file-selection

Mostrar una finestra amb un text informatiu

zenity –info –text=”Aquest és el text informatiu”

Mostrar una llista de sel·lecció

zenity –list –text=”Llista de prova” \
       –column=”ID” –column=”Nom” –column=”Valor” \
       “1” “nom1” “valor1” \
       “2” “nom2” “valor2” \
       “3” “nom3” “valor3” \
       “4” “nom4” “valor4”

Mostrar una icona de notificació al quadre del Gnome

zenity –notification  –text=”Text de la notificació”

Mostrar una barra de progrés. El truc per a que funcioni és el tub (pipe) que alimenta la progressió de la barra.

(
for i in {1..100}
do
   echo $i
done
) | zenity –progress –text=”Exemple de barra de progrés” –auto-close –percentage=0

Demanar a l’usuari si sí o si no a una pregunta.

if zenity –question –text=”Vols continuar?” –ok-label=”Sí, està molt interessant” –cancel-label=”No, m’avorreixo com una ostra”
then
    zenity –info –text=”Ok, doncs seguim.”
else
    zenity –error –text=”Cap problema, un altre dia serà.”
fi

Mostrar un fitxer de text

zenity –text-info –filename=”help.txt” –height=400 –width=500

Mostrar un text d’alerta. Adonem-nos que zenity ens proporciona caixes de notificació específiques de info, warning i error, que són els tres nivells que es fan servir més habitualment per a classificar per importància o gravetat els missatges de les aplicacions.

zenity –warning –text=”Aquest és un text d’alerta”

Finalment, obtenir un valor numèric dins un rang

zenity –scale –text=”Quants anys tens?” –min-value=0 –max-value=150

Taules amb cantonades rodones (reprise)

En un post anterior vaig explicar com  fer caixes amb els cantons rodons amb HTML.

En aquella ocasió la solució es basava en taules HTML aplicant estils a etiquetes <table> <tr> i <td>.

En ocasions , un enfocament com l’anterior pot ser necessari, perquè hi han un munt de pàgines web que fan servir, o han fet servir, les taules per a maquetar-ne la presentació, i pot ser que ens calgui retocar-les.

Des de fa temps, però, la solució amb taules es considera inadequada. Les taules HTML només haurien de fer-se servir per presentar dades en format tabular, i formatar-les amb css.

Per a maquetar, la recomanació general és fer servir capes (etiquetes <div>). Per al cas concret de taules amb cantons rodons, vet aquí solucions possibles.

Si em cal crear els gràfics corresponents a les caixes amb els cantons rodons, faig servir la combinació de Inkscape i Gimp. Inkscape permet crear caixes amb cantons rodons, especificant mides i radis dels cantons,  aplicar diferents efectes i exportar les caixes a format png. Després, per retallar les diferents cantonades, les o tapes, o els costats, es pot fer servir el Gimp, per exemple.

OpenOffice.org/LibreOffice Draw també permet crear caixes amb els cantons rodons amb l’eina de dibuix caixa i fent, després Format-Posició i Mida i ajustant el radi a la pestanya Inclinació i Radi de la Cantonada. La pega de fer servir aquesta eina és que no disposa de la unitat “píxel”, d’us comú al disseny web. Si la fem servir segurament ens caldrà fer una conversió prèvia a les unitats de treball OOo/LO. Per exemple, fer servir punts, la conversió és 3pt aprox. igual a  4px.

El cas trivial és que coneixem d’antuvi la mida que tindrà la taula. En aquest cas, n’hi ha prou amb fer-servir la caixa de background d’un div:

<div class=”caixa”>Compte amb no sortir-se’n dels
marges pre-establerts.<br>
<ul>
  <li>ítem 1</li>
  <li>ítem 2</li>
  <li>ítem 3</li>
  <li>ítem 4</li>
  <li>ítem 5</li>
  <li>ítem 6</li>
  <li>ítem 7</li>
</ul>
</div>

i tindré la següent definició per a la class caixa:

.caixa {
  border-style: none;
  margin: 0px;
  padding: 5px;
  width: 401px;
  background-image: url(http://localhost/albert/prova01/img/quadre401x201px.gif);
  background-repeat: no-repeat;
  height: 201px;
  font-family: Arial,Helvetica,sans-serif;
  color: #000099;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
}

On la imatge és aquesta:

Pot ser útil  crear caixes que es redimensionin automàticament:

Aquesta és una caixa que pot  créixer en vertical. Cal fer tres capes: una capa per la tapa superior, una capa central, i una capa per a la tapa inferior.

<div class=”topbox”>&nbsp;</div>

<div class=”midbox”>exemple de caixa que port créixer en
vertical. Només cal anar afegint text per veure com creix sense haver
de fer res més.<br>
</div>

<div class=”bottombox”>&nbsp;</div>

Les css corresponents:

.topbox {
  background-image: url(img/top-quadre301x12px.png);
  width: 301px;
  height: 12px;
  background-repeat: no-repeat;
}
.midbox {
  padding: 5px;
  background-image: url(img/bg-quadre301x1px.png);
  width: 301px;
  font-family: Arial,Helvetica,sans-serif;
  font-size: 25px;
  background-repeat: repeat-y;
}
.bottombox {
  width: 301px;
  background-repeat: no-repeat;
  background-image: url(img/bottom-quadre301x12px.png);
  height: 12px;

Les mides de les imatges han de coincidir amb les dels div.

Les imatges de les tapes superior i inferior:

i la imatge central que és d’1 pixel d’amplada i que aconsegueix emplenar la capa en vertical amb el background-repeat: repeat-y

 

De forma similar, es pot crear una caixa capaç d’adaptar-se, fins un tamany màxim, a divrerents llargades horitzontals. Em cal una tapa a l’esquerra, una capa central i la tapa de la dreta. Aleshores cal indicar que la imatge central ha de repetir-se en horitzontal.
Com cal posar les capes una a continuació de l’altre, cal indicar que “floten”:

<div class=”leftbox”>&nbsp;</div>

<div class=”midbox2″>exemple de caixa que pot créixer en
horitzontal fins un màxim de 900px. Cal vigilar perquè tindrà un màxim
de línies útils.<br>
</div>

<div class=”rightbox”>&nbsp;</div>

Els css corresponents són:

.leftbox {
  background-image: url(img/left-quadre12x151px.png);
  background-repeat: no-repeat;
  height: 151px;
  width: 12px;
  float: left;
}
.midbox2 {
  padding: 5px;
  background-repeat: repeat-x;
  float: left;
  font-family: Arial,Helvetica,sans-serif;
  background-image: url(img/bg-quadre1x151px.png);
  height: 151px;
  max-width: 900px;
  font-size: 40px;
}
.rightbox {
  background-image: url(img/right-quadre12x151px.png);
  background-repeat: no-repeat;
  width: 12px;
  height: 151px;
  float: left;
}

Les imatges són:

En aquest últim cas,  caldrà tenir en compte que les dimensions de la pantalla poden provocar que alguna capa passi a la fila inferior, desmuntant l’efecte de caixa. Es pot prendre la precaució d’agrupar les tres capes anteriors en una capa de dimensions suficients i que forçaria l’aparició de la barra d’scroll horitzontal si calgués.

Finalment, pot ser interessant disposar d’un mètode general per a fer caixes de mida ajustable.

El següent és una tècnica adaptada de http://www.neuroticweb.com/recursos/css-rounded-box/. Amb aquesta tècnica només cal fixar la mida horitzontal.

Com en els casos anteriors tindrem una tapa superior, una capa central i una capa de tapa inferior.  Però les tapes tindran, a més sengles capes addicionals per a fer cada una la cantonada dreta corresponent.

Vet aquí el codi. Podem ampliar el text o posar i treure <br> per veure’n els resultats.

<div class=”rbbox”>

    <div class=”rbltop”>
        <div class=”rbrtop”>&nbsp;</div>
    </div>

    <div class=”rbcontent”>
        <p>aquesta és una prova de caixa que s’adapta de forma<br>
        automàtica a la mida del seu contingut.<br>
        Adaptat de 

        <a href=”http://www.neuroticweb.com/recursos/css-rounded-box/”&gt;
        http://www.neuroticweb.com/recursos/css-rounded-box/</a></p&gt;
    </div>

    <div class=”rblbot”>
        <div class=”rbrbot”>&nbsp;</div>
    </div>
</div>

Els css són aquests:

.rbbox { background: url(img/rbbg.gif) repeat; width: 300px; margin: 0 100px; }
.rbltop { background: url(img/rbtl.gif) no-repeat top left; }
.rbrtop { background: url(img/rbtr.gif) no-repeat top right; }
.rblbot { background: url(img/rbbl.gif) no-repeat bottom left; }
.rbrbot { background: url(img/rbbr.gif) no-repeat bottom right; }
.rbcontent { margin: 5px 5px; }

I les imatges:

Finalment, dir que de tècniques per a fer cantonades rodones amb HTML i CSS  n’hi han moltes. A aquest enllaç (http://www.devwebpro.com/25-rounded-corners-techniques-with-css/) en podem trobar un bon grapat.

Com fer servir wget per a descarregar llocs web sencers

Un “truc” amb Linux. Com descarregar-se una web sencera?

En general, la resposta és amb una aranya web (o web crawler): un programa que es dedica a recorrer els enllaços d’una pàgina web de forma recursiva fins a un determinat nivell de profunditat.

Ara bé, a Linux hi ha una petita aplicació de línia de comandes que permet fer exactament això mateix: wget

Per a descarregar una web “sencera” podem fer-ho amb:

Si fem wget –help a un terminal obtenim la llista d’opcions. En particular es veu que:

Descàrrega recursiva:
-r, –recursive       baixa de forma recursiva.

-l, –level=NOMBRE    nivell màxim de recursió (inf o 0 per infinit)

Al manual de GNU Wget trobem tota la informació sobre aquest programa.