Jun 28

Cheetah – the python powered template engine

Reading time: 2 – 3 minutes

Un article ‘fast-n-dirty’ sobre potser la millor llibreria que he trobat per treballar amb templates i python: Cheetah. Es tracta de poder generar fitxers de texte de forma senzilla: fitxers de configuració, pàgines web, emails, etc. a partir de plantilles. Realment útil en molts entorns.

Les funcionalitats (copy-paste de la web):

  • is supported by every major Python web framework.
  • is fully documented and is supported by an active user community.
  • can output/generate any text-based format.
  • compiles templates into optimized, yet readable, Python code.
  • blends the power and flexibility of Python with a simple template language that non-programmers can understand.
  • gives template authors full access to any Python data structure, module, function, object, or method in their templates. Meanwhile, it provides a way for administrators to selectively restrict access to Python when needed.
  • makes code reuse easy by providing an object-oriented interface to templates that is accessible from Python code or other Cheetah templates. One template can subclass another and selectively reimplement sections of it. Cheetah templates can be subclasses of any Python class and vice-versa.
  • provides a simple, yet powerful, caching mechanism that can dramatically improve the performance of a dynamic website.
  • encourages clean separation of content, graphic design, and program code. This leads to highly modular, flexible, and reusable site architectures, shorter development time, and HTML and program code that is easier to understand and maintain. It is particularly well suited for team efforts.
  • can be used to generate static html via its command-line tool.

a qui va orientat (copy-paste de la web):

  • for programmers to create reusable components and functions that are accessible and understandable to designers.
  • for designers to mark out placeholders for content and dynamic components in their templates.
  • for designers to soft-code aspects of their design that are either repeated in several places or are subject to change.
  • for designers to reuse and extend existing templates and thus minimize duplication of effort and code.
  • and, of course, for content writers to use the templates that designers have created.

Jun 16

Somiant amb una extenció pel Gearman

Reading time: 5 – 8 minutes

Cal dir que no sóc massa ordenat al presentar noves tecnologies ja que primer de tot vaig fer un bechmark sobre Gearman abans de fer-ne una introducció, doncs bé com que en aquest article vull parlar sobre unes possibles extensions sobre les que vull treballar amb Gearman primer de tot faré una petit introducció al projecte.

Introducció

Gearman és el que comunment anomenem un servidor de tasques, o sigui, que quan el nostre codi ha de demanar una tasca, funcionalitat, treball, o quelcom similar és molt interessant de cara a:

  • l’escalavilitat: podem tenir tants servidors i/o processos consumint tasques com ens interessi.
  • paral·lelisme: les tasques es poden consumir paral·lelament.
  • balanceix de càrrega: podem fer map/reduce sobre les tasques i enviar-les als servidors que ens interessis per distribuir la càrrega.
  • independència entre lleguatges: el codi que demana la tasca i el que consumeix la tasca poden ser totalment diferents, les llibreries que té Gearman són: PHP, Pearl, Ruby, C, Python, etc.
  • interficie HTTP: a més disposa d’una interficie client HTTP que ens permetra injectar tasques desde llenguatges no suportats des de les llibreries de Gearman.

usar un servidor d’aquest tipus, ja que a més de permetrens demanar tasques síncrones, també podem demanar-li tasques asíncrones. O sigui, que no només no sabem qui ens esta fent la feina limitant-nos a rebre’n el resultat sinó que també podem demanar que aquesta feina es faci quan es pugui.

Per si tot això no fos poc encara hi ha més avantatges:

  • Open Source
  • Programat en C
  • Petit i molt ràpid
  • Suporta diversos backends: RAM, SQLite, Memcached, Tokyo Cabinet, etc.

gearman stack

La gent que va començar a implementar Gearman, van ser els de Danga Interactive famosos per LiveJournal i SixApart.

Les meves idees

Després d’aquesta introducció, ara ja puc parlar de les coses que voldria que fes Gearman però que no fa. Primer de tot he de parlar de les avantatges que tindria si pogués tenir un backend contra Redis. El que persegueixo al connectar Redis amb Gearman és aconseguir:

  • persistència de tasques malgrat es reiniciï Gearman
  • persistència de tasques en disc malgrat es reinciï Redis, gràcies a:
    • l’escriptura asíncrona a disc
    • bgrewriteaof: evita que per l’escriptura asíncrona d’informació es perdin dades al reinciar bruscament Redis
  • publicar a un canal PubSub de Redis els canvis que es fan sobre una tasca que s’ha enviat a ‘background’

Integració amb Redis

Es tracata de fer el mateix que s’ha per integrar backend de tokyo cabinet: queue_libtokyocabinet.c el problema d’usar tokyo cabinet contra disc és la pèrdua brutal de rendiment respecte a usar-lo contra RAM, ja que les escriptures es fan de forma síncrona.

A nivell de codi les semblances més grans són amb: queue_libmemcached.c, malgrat el problema que té aquesta implementació és que cada cop que reiniciem memcached no tenim persistència de la informació que s’havia guardat en memcached, és com si les claus que s’han intrudit en l’anterior sessió s’haguessin esborrat. A més memcached no suporta persistència en les seves dades tampoc.

Així doncs, el que cal fer és agafar el millor d’amdues integracions i fer el mòdul amb Redis.

Subscripció a les actualitzacions d’una tasca via Redis

Quan s’envia una tasca en segon pla a Gearman aquest ens retorna un ‘Handler’ per poder preguntar sobre l’estat de la tasca, el problema és que si volem saber com evoluciona la tasca o que ens informi quan ha acabat no hi ha manera de saber-ho si no és fent ‘pooling’. Per altre banda, el ‘worker’ va actualitzant la tasca cada quan creu convenien perquè Gearman pugui saber quin és l’estat de la mateixa.

La meva idea és que al usar el backend de Redis, al mateix moment que s’actualitzi l’estat de la tasca també es publiqui (publish) a un canal PubSub de Redis de forma que el codi que ha enviat la tasca pugui subscriures (subscribe) a aquest canal i en temps real i amb un cost de recursos baixíssim es pugui seguir l’estat de la tasca. Això ens evitaria la necessitat de que Gearman hagués de poder cridar un mètode de callback per informar-nos de l’estat de la mateixa, ja que hi ha alguns llenguatges en que fer això no és tan senzill.

En el gràfic que enganxo a continuació podem veure un esquema que he fet sobre això:

esquema idees de Gearman amb Redis

1) el nostre codi envia una tasca en ‘background’ (segon pla) a Gearman i aquest li torna un ‘Handler’ per identificar la tasca.

2) es guarda la tasca a Redis (set)

3) el nostre codi es subscriu al canal PubSub de la tasca

4) un worker demana la tasca

5) es publica l’estat de la tasca

6) es va actualitzant l’estat de la tasca

7) es van repetint els punts (5) i (6) fins acabar la tasca

Feedback

Com sempre s’accepten tota mena de crítiques i idees sobre la meva ‘paranoia’.

Apr 22

Integració continua: buildbot + codespeed + guppy-pe + resource

Reading time: 3 – 4 minutes

Degut a un requeriment que teniem a la feina he montat un entorn d’integració continua. En escència el que es busca és el següent:

  • Llençar de forma automàtica tests sobre els commits que es fan al codi (buildbot)
  • Tenir un repositori dels resultats dels tests fàcil de consultar (web) (buildbot)
  • Suportar tests sobre rendiment (profiling) automàtics (guppy-pe + resource)
  • Poder comprovar quina és l’evolució d’aquests tests de rendiment amb una eina visual (codespeed)

Per tal d’aconseguir aquests objectius s’ha usat:

  • buildbot: que permet automatitzar l’entorn de compilació i testeix dels commits que es van fent al repositori. (esta programat en python). Per entendre millor buildbot, ús recomano llegir l’apartat: system architecure del seu manual.
  • codespeed: és una eina feta amb python+django+mysql a través d’una interficie HTTP+JSON pot injectar informació a la BBDD i a través de la GUI ens mostra:
    • overview: a través d’una taula mostra les tendències dels resultats dels benchmark associats a un executable.
    • timeline: mostra en una gràfica l’evolució dels resultats arxivats sobre un benchmark concret fets sobre un host.
  • guppy-pe: ens permet extreure dades referents als recursos de sistema que esta consumint una part del codi: classe, funció, variable, etc.
  • resource: és un módul de python que permet saber (resource.getrusage(PID)) quins recursos esta consumint un PID en un moment donat.

Com que la documentació que he fet per la feina l’he hagut de filtrar per no revelar informació interna, la documentació que publico esta en format OpenOffice i PDF perquè sigui senzill per tothom llegir-la i modificar-la si vol.

  • Paquet .tar.gz, conté:
    • fitxer de configuració buildbot, master.cfg
    • codi d’exemple per provar l’entorn, buildbot-test
    • codi del tobami-codespeed modificat perquè sigui més generalista que la versió original
    • integracion-continua-instalacion.odt: document amb notes sobre els procediments que he seguit per la instal·lació de tot plegat.
    • integracion-continua-manual.odt: manual d’usuari de tot plegat. (també la versió en pdf)
  • integracion-continua-manual.pdf: enllaço de forma directa aquest manual per si hi voleu donar un cop d’ull per saber si ús interessa el tema.

Enllaços relacionats:

Apr 21

dues versions de python en un host

Reading time: < 1 minute A vegades cal fer algún invent extrany amb el python, com per exemple, el haver de tenir dues versions instal·lades. Sovint la nostre distribució ja portarà una versió del mateix i a més moltes eines de les distribucions acostumen a anar lligades a aquesta versió que millor no malmetre. Cookbook d'ordres per instal·lar un python 2.6.5 a més del 2.4.3 que ja portava el host:

cd /var/tmp
wget http://python.org/ftp/python/2.6.5/Python-2.6.5.tar.bz2
tar xvfj Python-2.6.5.tar.bz2
cd Python-2.6.5
./configure –prefix=/usr
make
make altinstall

si ara fem:

# python -V
Python 2.4.3
# python2.4 -V
Python 2.4.3
# python2.6 -V
Python 2.6.5

Feb 12

eines per XMPP

This entry is part 4 of 4 in the series xmpp

Reading time: 2 – 3 minutes

A continuació adjunto una petita descripció d’algunes eines per comunicar-se amb una xarxa XMPP que poden ser molt útils:

Idavoll

Implementació del XEP-0060, o sigui, d’un servei de publish-subscribe (PubSub) esta escrit amb Python i Twisted. Bàsicament el que permet és que sobre un servidor XMPP estàndard hi podem connectar un servei basat en PubSub, o sigui, que nosaltres publiquem una serie d’informació que un seguit de clients consulten perquè hi estan subscrits. És un mètode basat en events (no-polling) molt adient per disfondre certs tipus d’informació.

Switchboard

A vegades programem shell scripts que necessiten enviar el seu resultat a la xarxa XMPP, per exemple, imagineu que volem comunicar la caiguda d’un servei a través de GTalk, doncs aquest toolkit ens simplifica moltíssim aquesta tasca. Esta programat en ruby i a part de poder-se usar des de la CLI també podem integrar-ho com a llibreria dins d’un codi en ruby.

XMPP Poetry CLI tools

El seu nom ja ho diu tot, són una col·lecció d’eines que via CLI ens permeten interactuar amb una xarxa XMPP, algunes de les seves funcions són:

  • disco: recull informació sobre serveis
  • pubsub-config: crea, configura i llança queries contra serveis pub-sub

Aquestes eines estan escrites amb Python, Twisted i Wokkel.

XMPPPHP

Llibreria de PHP5 amb suport de:

  • XMPP 1.0 (pot connectar a: GTalk, LJTalk, jabber.org, etc)
  • Suporta TLS
  • Processa diversos formats XML

Sembla força senzill d’usar, per exemple, programar un bot és tan fàcil com això:

<?php
include("xmpp.php");
$conn = new XMPP('talk.google.com', 5222, 'user', 'password', 'xmpphp', 'gmail.com', $printlog=True, $loglevel=LOGGING_INFO);
$conn->connect();
while(!$conn->disconnected) {
    $payloads = $conn->processUntil(array('message', 'presence', 'end_stream', 'session_start'));
    foreach($payloads as $event) {
        $pl = $event[1];
        switch($event[0]) {
            case 'message':
                print "---------------------------------------------------------------------------------\n";
                print "Message from: {$pl['from']}\n";
                if($pl['subject']) print "Subject: {$pl['subject']}\n";
                print $pl['body'] . "\n";
                print "---------------------------------------------------------------------------------\n";
                $conn->message($pl['from'], $body="Thanks for sending me \"{$pl['body']}\".", $type=$pl['type']);
                if($pl['body'] == 'quit') $conn->disconnect();
                if($pl['body'] == 'break') $conn->send("");
            break;
            case 'presence':
                print "Presence: {$pl['from']} [{$pl['show']}] {$pl['status']}\n";
            break;
            case 'session_start':
                $conn->presence($status="Cheese!");
            break;
        }
    }
}
?>

Oct 24

Python: afegir suport de plug-ins al nostre codi

Reading time: 6 – 9 minutes

A vegades quan estem fent un programa ens interessa que el nostre codi pugui ser extés sense haver de tocar la seva estructra, fins hi tot el que ens pot interessar és que aquest codi sigui extés en algunes ocasions i en d’altres no. Un altre requeriment que podem tenir també seria que qui l’extengui no siguem nosaltres. Sovint tot això i molt més s’acostuma a fer amb el que anomenem Plug-ins, per cert, sempre m’ha fet molta gràcia la traducció al català de la paraula: ‘afegitons’.

Doncs bé, com que jo de programació no hi entenc gaire li vaig demanar al Pau que m’ajudés a entendre els models de plug-ins que implementaven alguns programes fets amb Python, ja que m’ineressava integrar aquesta funcionalitat en una serie de codis que estic desenvolupament. En aquest post intentaré explicar com funciona el paradigma dels plug-ins que usa Trac.

Primer de tot cal tenir en compte que Trac usa un patró de desplegament d’objectes anomenat Singleton, o sigui que totes les instàncies d’un objecte es refereixes a la mateixa instància. De fet, no sé dir fins a quin punt és necessari que el codi segueixi aquest patró per usar el sistema de plug-ins; tot i que jo diria que almenys les parts del codi que vulguin ser exteses pel model de plug-ins de Trac l’han de seguir.

Els plug-ins de Trac tenen les següents característiques:

  • Un Plug-in és un component que extent la funcionalitat d’un altre component
  • Un Plug-in pot extendre un altre Plug-in

Per tal d’incorporar la filosofia que té Trac per suportar Plug-ins al nostre codi cal importar el component ‘trac.core’, d’aquest component usarem el següent:

  • trac.core.Interface (classe) s’usa per definir quin és el contracte que hauran de seguir els plug-ins.
  • trac.core.ExtensionPoint (funció) quan volem que un component sigui extés usarà aquesta funció per recuperar les implementacions del contracte. Deifineix els punts de hook que té el nostre codi.
  • trac.core.implements (funció) quan un component usa aquesta funció és per implementar un contracte, o sigui, que els plug-ins que es construeixin l’han d’usar.

Abans de seguir explicaré que s’enten per contracte. Un contracte és en escència una classe de tipus interficie (python no té aquest model com a tal) que defineix quins mètodes (o altres classes) poden ser extesos dins el component original. O sigui, que cal no només definir quin és el contracte que s’ofereix sinó també documentar-lo el millor possible, explicant quines són les entrades i sortides que s’esperen de cada un dels mètodes/classes.

Perquè tot plegat s’entengui millor el Pau em va posar el següent exemple:

Imaginem que tenim una classe del tipus DNI que implementa una base de dades de DNIs, on té un metode que ens permet entrar DNIs a la base de dades:

class DNI(trac.core.Component):
  dni_checks = trac.core.ExtensionPoint(IDNIInput)
  def __init__(self):
     self._dnis = []
  def add(self, dni):
     assert not dni in self._dnis, "DNI ja existeix"for dni_check in self.dni_checks:
     if dni_check.check(dni) is False:
       print "El dni %s  sembla no ser correcte" % ( dni )
       return
    self._dnis.append(dni)
  def llista(self):
    print self._dnis

Cal fixar-se que la línia:

dni_checks = trac.core.ExtensionPoint(IDNIInput)

el que fa és carregar els plug-ins que extenen la funcionalitat del codi original. A més cal que ens fixem que el paràmetre que usa la funció és la classe que defineix el contracte sobre el que es fan els plug-ins:

class IDNIInput(trac.core.Interface):
  def check(dni):
    """ Es cridada cada cop que s'entra un nou dni, espera que es retorni un valor boleà"""

Com es pot veure el contracte només defineix un mètode: ‘check’ que ha de tenir un paràmetre d’entrada i espera un valor boleà de sortida.

Cal fixar-se en que la classe DNI cada vegada que afegeixi un element a la base de dades (en aquest cas una simple llista), cridarà a tots els plug-ins que compleixin el contracte per l’ordre en que s’han instanciat (s’han importat al codi original) mitjançant el següent codi.

for dni_check in self.dni_checks:
  if dni_check.check(dni) is False:
    print "El dni %s  sembla no ser correcte" % ( dni )
    return

Un exemple de plug-in sobre el codi anterior i que compleix el contracte especificat podria ser aquest:

import trac.core
import dni
class ValidDNI(trac.core.Component):
  trac.core.implements(dni.IDNIInput)
  def check(self, dni):
    if type(dni) is not type("str"):
      return False
    if len(dni) != 9:
      return False
    return True

Es pot veure com la classe és una instància de ‘trac.core.Component’ (model Singleton) i implementa la interfice ‘dni.IDNIInput’. A nivell funcional el que es fa és ben simple, comprovem que sigui una cadena de texte i que tingui una mida de 9 caràcters, si això es dona retorna un ‘True’ o sinó un ‘False’.

Un exemple de com quedaria el codi principal seria:

import trac.core                                                           

class IDNIInput(trac.core.Interface):
  def check(nom):
    """ Es cridada cada cop que s'entra un nou dni"""
class DNI(trac.core.Component):
  dni_checks = trac.core.ExtensionPoint(IDNIInput)
  def __init__(self):
    self._dnis = []
  def add(self, dni):
    assert not dni in self._dnis, "DNI ja existeix"
    for dni_check in self.dni_checks:
      if dni_check.check(dni) is False:
        print "El dni %s  sembla no ser correcte" % ( dni )
        return
    self._dnis.append(dni)
  def llista(self):
    print self._dnis

Exemples d’ús:

>>> import trac.core
>>> from dni import DNI
>>>
>>> dni_bd = DNI(comp_mgr)
>>> dni_bd.add("38135009C")
>>> dni_bd.add("38135009")
>>> dni_bd.llista()
['38135009C', '38135009']

# importem el plug-in check_dni
>>> import check_dni
>>> dni_bd.add("11111111")
El dni 11111111  sembla no ser correcte
>>> dni_bd.add("11111111A")
>>> dni_bd.llista()
['38135009C', '38135009', '11111111A']

Definim el codi ‘log_dni’ que serà un altre plug-in:

import trac.core
import dni
class LogDNI(trac.core.Component):
  trac.core.implements(dni.IDNIInput)
  def check(self, dni):
    print "Nou dni entrat %s" % (dni)

Seguim amb l’exemple anterior:

# importem ara el plug-in 'log_dni'
>>> import log_dni
>>> dni_bd.add("22222222B")
Nou dni entrat 22222222B

A aquestes altures ja s’han carregat dos plug-ins que treballen un després de l’altre i s’ha pogut apreciar la simplicitat i potència del model. Obviament es poden trobar coses a faltar com per exemple algún element que defineixi el llistat de plug-ins disponibles i que permeti alterar l’ordre en que aquests s’executen però això ja s’hauria de desenvolupar a part.

Espero haver-ho descrit de forma entenedora i sent el més fidel possible a les explicacions del Pau, al que he d’agrair-li l’esforç i dedicació per explicar-me aquest model de Plug-ins de Python.

Jul 30

cookbook: python logging

Reading time: 2 – 3 minutes

Sovint faig molts scripts de sistema usant python com a llenguatge de programació, doncs bé, sobretot quan aquests scripts s’han de llençar usant el ‘crontab’ va molt bé tenir un bon ‘log’ per saber com van les coses. Així doncs, la setmana passada vaig decidir posar-me a fons amb el tema ‘logging’ de python i ara la forma de fer ‘logs’ que uso per defecte en els meus scripts és:

Snippet de codi python que poso als scripts:

import  logging,logging.config
# logging
logging.config.fileConfig('script_logging.ini')
#logger = logging.getLogger('errorpantalla')
logger = logging.getLogger('errorfitxer')
logger.setLevel(logging.INFO)

Després d’importar la llibreria de ‘logging’ es recuperar el fitxer de configuració on estan definits els paràmetres de ‘logging’.  Un cop carregat, descomento una o les dues línies que hi ha a continuació en funció de si vull logs per pantalla o només contra un fitxer. La última línia només indica fins a quin nivell de depuració he de fer mostrar logs.

El fitxer de configuració:

[loggers]
keys=root,errorpantalla,errorfitxer

[handlers]
keys=fitxer,pantalla

[formatters]
keys=form01

[logger_root]
level=DEBUG
propagate=1
channel=
parent=
qualname=(root)
handlers=

[logger_errorpantalla]
level=DEBUG
propagate=1
channel=errorpantalla
parent=(root)
qualname=errorpantalla
handlers=pantalla

[logger_errorfitxer]
level=DEBUG
propagate=1
channel=errorfitxer
parent=(root)
qualname=errorfitxer
handlers=fitxer

[handler_fitxer]
class=handlers.RotatingFileHandler
level=DEBUG
formatter=form01
filename=paht_to_log_file/log_file
mode=a
maxsize=0
backcount=1
args=('paht_to_log_file/log_file', 'a', 0, 1)

[handler_pantalla]
class=StreamHandler
level=DEBUG
formatter=form01
stream=sys.stderr
args=(sys.stderr,)

[formatter_form01]
format=%(asctime)s %(levelname)s %(message)s
datefmt=

A més vaig trobar un petit script, que carrega una GUI per generar les configuracions dels fitxers de configuració dels ‘logs’, realment útil i simple d’usar:

logging configurator for python

Aquesta GUI l’he trobada al paquet: logging-0.4.9.6.tar.gz concretament al directori ‘tests’. Si no voleu buscar tant també podeu descarregar-lo directament: logconf.py.

Jul 26

Conceptes de Clutter

Reading time: 6 – 9 minutes

Des de fa uns mesos m’he posat a fons amb Clutter, es tracta d’una API més una ABI programada en C per crear interficies d’usuari. Malgrat tractar-se en escència d’una API per crear espais 3D amb objectes 2D, té la capacitat de poder moure els objectes en la coordenada Z. Així doncs, és pot aprofitar la potència d’OpenGL de forma transparent i senzilla i sense haver-se de preocupar de com representar objectes 2D en espais 3D, cosa gens senzilla per un neofit en el món dels gràfics com jo.

Clutter usa el seu propi reactor d’events, però en certs casos pot usar Gobject, Glib i Gtk també. És fàcilment integrable amb DBUS i amb GStreamer. En escència m’ofereix tot el que em cal per un projecte que porto entre mans. Pels que encara no ho tingueu clar, l’interficie gràfica que usa Moblin esta programada amb Clutter com a llibreria gràfica. De fet, és aquest projecte el que li ha donat molta força a Clutter que disposa de 29 programadors a temps complet, dels quals 14 no són d’intel (intel és qui promociona amb més força ‘moblin’).

Bé doncs, aquest impuls que ha patit moblin l’han portat a la versió 0.9.8 que és realment potent i ja gairebé igual que la versió 1.0 que hauria de sortir en breu. Tot i que fins ara Clutter s’ha caracteritzat pel retard en la sortida de les noves versions esperem que aquest cop no sigui així.

Abans d’entrar a definir quins són els elements que té aquesta llibreria, comentar que també disposa de binding de python cosa que pels ‘no-programadors’, com jo, és tota una alegria. També s’ha de dir que a dia d’avui, no hi ha bindings oficials per la branca 0.9 de Clutter que és l’experimental, o futura 1.0. Així doncs, jo només he provat el Clutter fins a la seva versió 0.8, malgrat la segueixo amb lupa la versió 0.9.x; a l’espera de poder començar a fer coses amb ella quan tingui els bindings de python.

Anem al motiu central de l’article, repassar els conceptes que usa Clutter fins a la verió 0.8:

  • Stages: una aplicació de Clutter conté almenys un ‘stage’, aquests contenen actors que són: imatges, rectangles, textos, etc. Un ‘stage’ es comporta de forma semblant a un ‘canvas’ (tapís).
  • Stage Widget: Podem contenir un ‘stage’ dintre d’un objecte finestre de GTK+. En aquests casos es pot usar GTK com a reactor d’events.
  • Actors:  són formes 2D mostrades en un espai 3D. Aquestes formes poden ser; per exemple, formes geomètriques, imatges, textos, etc. Si el que cal és tenir actors tridimencionals en aquest espai el que caldrà és instanciar directament l’API d’OpenGL.  Per mostrar un actor en un ‘stage’ cal fer-ho a través d’un ‘container’.
  • Transformations: es refereix a les transformacions que li podem fer a un ‘actor’ al mostrar-lo:
    • Scaling: aumentar o disminuir la seva mida aparent, no la real.
    • Rotation: es pot rotar sobre els seus eixos X, Y i Z.
    • Clipping: fixar l’objecte sobre el ‘canvas’ això ens permet per exemple, crear una zona d’scrolling al seu intererior.
    • Movement: desplaçar les coordenades de posició de l’objecte.
  • Containers: en si mateix és un tipus especial d’actor, compost per altres actors fills que es posicionen en l’espai respecte la posició del seu contenedor. De fet, si ens hi fixem el propi ‘stage’ és un ‘actor’ de tipus ‘container’. Escencialment hi ha dos tipus de ‘containers’: ClutterContainer i ClutterGroup.
  • Events: la classe ‘actor’ emet una serie de senyals que podem capturar per enllaçar amb funcions, les senyals són:
    • button-press-event: emès quan l’usuari prem el botó del ratolí sobre l’actor.
    • button-release-event: emès quan l’usuari deixa anar el botó del ratolí sobre l’actor.
    • motion-event: quan el ratolí es mou per sobre l’objecte.
    • enter-event: emès a l’entrar sobre la superficie de l’actor.
    • leave-event: emès al sortir de la superficie de l’actor.
  • Timelines: es poden usar per canviar la posició o aparença d’un actor al llarg del temps. Les línies de temps es poden usar soles o amb combinació dels ‘effects’ i els ‘behaviours’. Per cada ‘frame’ que s’ha de dibuixar en el temps s’emet una senyal anomenada ‘new-frame‘, obviament la podem connectar a alguna funció. Al crear una línia de temps hem d’espificar dos paràmetres: la quantitat total de ‘frames’ que tindrà i els ‘frames per segon’ a la que es reproduirà.
  • Score: podem agrupar diverses ‘timelines’ en un ‘score’, això ens permet posar en marxa o parar diverses ‘timelines’ a la vegada.
  • Effects: són una serie de funcions que podem aplicar sobre els actors usant una ‘timeline’ amb l’objectiu de canviar les propietats al llarg del temps, usant un simple càlcul numèric. Sovint aquesta és la forma més simple de crear una animació. És important recordar que els efectes només poden afectar a un actor en una ‘timeline’ i no podem canviar els efectes al llarg del temps, per fer això cal fer-ho amb un ‘behaviour’.
  • Behaviours: tenen la capacitat de canviar una propietat específica d’un actor al llarg del temps aplicant un simple càlcul numèric. A diferència dels ‘effects’ amb els ‘behaviours’ podem controlar més d’un actor a la vegada i canviar els paràmetres dels càlculs que es fan al llarg de la ‘timeline’. Un exemple ben senzill d’aplicació d’això seria que podem fer que la funció que es crides al llarg del temps detecti que s’ha acabat l’efecte aplicat i el faci tornar a començar automàticament, simplement canviant el paràmetre de l’efecte que s’esta aplicant. Els ‘behaviours’ que té Clutter per defecte són:
    • ClutterBehaviourBspline: mou l’actor a través una línia ‘bezier‘.
    • ClutterBehaviourDepth: mou un actor a l’eix Z.
    • ClutterBehaviourEllipse: mou un actor al llarg d’una el·lipse.
    • ClutterBehaviourOpacity: canvia l’opacitat d’un actor.
    • ClutterBehaviourPath: mou un actor al llarg d’un camí definit per una serie de punts.
    • ClutterBehaviourRotate: rotar un actor.
    • ClutterBehaviourScale: canvia la mida aparent d’un actor.

Per fer aquesta referència m’he basat amb la informació de la guia ‘Programming with Clutter‘ escrita per Murray Cumming.

Mar 27

python trick: compartir directori via HTTP

Reading time: 1 – 2 minutes

A vegades estant en la propia LAN, suem tinta per dir-li a un usuari de windows com ho ha de fer per agafar un fitxer d’un directori del nostre linux. Si teniu python instal·lat, normalment totes les distribucions l’instal·len per defecte a més del paquet HTTP. Podeu fer una cosa tan simple com posar al .bashrc:

alias quickweb='python -c "import SimpleHTTPServer;SimpleHTTPServer.test()"'

Ara aneu al directori on voleu compartir els fitxers i escriviu: quickweb. Això obrirà el vostre port 8000 i qualsevol usuari de la xarxa podrà connectar-se amb el navegador a la vostre IP pel port 8000. Allà es pot veure i descarregar els fitxers que hi teniu. Quan volgueu deixar de compartir el directori només cal fer un Control+C i llestos.

Realment una xorrada molt i molt útil, no? si voleu comprovar què esteu compartint ja ho sabeu: http://127.0.0.1:8000. Més senzill impossible.