Ja tornem a ser al peu del canó, adéu Punta Cana!
L’any passat l’Estefania i jo varem canviar l’any a la Riviera Maya i aquest any després de comprovar que fer el canvi d’any amb banyador és tot un plaer ho hem fet a Punta Cana (Republica Dominicana). Així doncs, del dia 29 de desembre fins el 5 de gener hem estat a l’hotel Catalonia Royal Bavaro on ens han tractat com uns senyors. Com sempre el principal atractiu de la zona ha estat la calor, el sol, la platja, la piscina i perquè no dir-ho el tot inclòs que hem disfrutat d’allò més. A continuació ús adjunto algunes fotografies que descriuen una mica el que ha estat aquest viatge.
Primer de tot unes vistes de pel·lícula per descriure la platja de l’hotel:
Una gran sort, els bons amics que varem fer al viatge: (per cert, l’hotel estava ple de catalans)
L’única escapada que varem fer de l’hotel va ser per anar al centre comercial Iberia (un tipus Carrefur) per fer les compres típiques i el sopar que varem fer a Higüey, concretament al bulevar. Per cert, erem els únics no domincans de la zona i es podia respirar l’ambient dominicà al 100%:
Una de les piscines de l’hotel a tocar de la platja:
I per tancar el recull una fotografia romantica amb un paissatge de somni:
Pels que tingueu curiositat a l’album de fotografies com sempre podeu trobar totes les fotografies del viatge.
Finalment he pujat a youtube un parell de videos, un de l’habitació de l’hotel tal com ja vaig fer l’any passat:
i un altre video, aquest de la discoteca Imagine de Punta Cana, on varem anar a celebrar la festa de cap d’any. Per cert, la discoteca esta dintre d’una cova i té tres sales de diferents estils de música malgrat per cap d’any només hi havia dues sales obertes:
Per fi agafo vacances, a Punta Cana falta gent
Demà marxem uns quants dies a Punta Cana (Republica Dominicana), de fet, anem a desconnectar de tot i a disfrutar de la calor, la platja, la piscina i bon menjar. En poques paraules a fer una mica de vegetals. Que l’any que ve ens espera un altre viatge també a la zona caribenya però amb una dosis d’aventura més gran. Esta bé això de fer un viatge sabent quin serà el següent no ho havia fet mai 🙂
Bé doncs, espero que acabeu de passar unes bones festes i si algú ens busca que no ho faci fins el 8 de gener, com a mínim.
Introducció a RestMS
XMPP és un protocol de missatgeria no només orientat a mantenir converses entre usuaris sinó també a ser usat com a sistema RPC entre diferents aplicacions. Malgrat això res és perfecte i AMQP més orientat a la segona funció que no pas a la primera es perfila com estàndard corporatiu molt més potent i eficient que XMPP en diversos aspectes. Però AMQP peca per ser força inaccessible degut a que no és trivial d’entendre i usar.
En tot aquest món de la missatgeria entre aplicacions hi ha un altre protocol no tan conegut però que preten tenir el millor d’XMPP i d’AMQP: RestMS. De fet, RestMS és realment una simplifiació d’AMQP que usa com a sistema de transport REST.
Es tracta d’un estàndard obert, amb una implementació Open Source força sòlida. Aquest estàndard ens aporta:
- sistema d’enrutat de missatges
- models de cues
- fàcil d’extendre la seva semàntica
- simple, perquè és precís i petit
- segur, usa els sistemes de seguretat estàndards d’HTTP
- escalable, perquè usa servidors, caches, proxies, etc. del món HTTP
- resol la dicotomia ‘polling vs events’ usant long-polling, igual que BOSH
- en principi no disposa de sistema de presència, tot i que es podria montar fàcilment
- pot codificar durant el transportar les dades en XML o JSON
- portable en diferents sistemes operatius
- ofereix interoperatibilitat entre diferents llenguatges de programació
Per tot plegat RestMS es perfila com una alternativa interessant per alguns entorns, aportant una solució simple i potent en molts aspectes. Tot i que teoria en mà, el trobo força més lent que no pas AMQP. De fet, des de que vaig veure com s’usava un sistema AMQP per fer balanceix de càrrega en aplicacions de video usant GStreamer per fer una prova ‘fast and dirty’ em vaig quedar impresionat.
- Article basat en la informació de: RestMS presentation
Tipus de pantalles tàctils
Després de treballar força anys en el món dels kioskos i del digital signage, mai se m’havia passat pel cap mirar-me quines eren les diferències reals entre els diferents tipus de pantalles tàctils que hi ha al mercat. Així doncs, finalment he decidit fer-ho i descriure-ho en aquest article.
Resistive Touch Screen
- La tecnologia amb la millor relació qualitat preu de totes les tecnologies tàctils
- Disponible per pantalles desde 5.7″ fins a 22″
- Compost per diferents capes:
- les més importants són dues capes fines: una metàlica i l’altre formada per capes conductores de l’ectricitat, aquestes capes són molt fines i estan separades entre elles molt poc espai
- quan un objecte, per exemple un dit, prem la pantalla llavors les capes metàliques es toquen i passen l’electricitat
- quan hi ha la connexió en aquest punt, el pantell actua com un divisor de voltatges en les sortides que tenen la connexió i registren l’event comunicant a la controladora que algú ha tocat la pantalla
- la tecnologia és força confiable, durable i acostuma a tenir un temps de vida llarg
- és la tecnologia més resisten en entorns ostils
- és económica
- és molt estable, és a dir no cal recalibrarla mai o quasi mai
- compatible en diferents tipus de tocs: dit, stylus, llapís, etc.
- ideal per aplicacions amb alta intensitat d’ús
- pot arribar a suportar els estàndars NEMA 4/4x/12 i IP 65
- si ens fixem bé en el tàctil a contrallum podem arribar a veure els minifilaments que el formen
- susceptible a rallades o esquerdes a la superficie de toc
Surface Acoustic Wave (SAW)
- la principal virtud és la seva transparència
- mides de 6.4″ a 42″
- usa ones ultra-sòniques que passen per sobre de la pantalla táctil
- quan es toca el tàctil una part de les ones és absorvida
- llavors es registre on han estat absorvides les ones i es comunica a la controladora el punt del toc
- la superfie de toc pot estar danyada i continua funcionant (ralles o vidre trencat)
- la brutícia sobre la superficie de toc pot interferir en el seu funcionament
- els tàctils d’aquest tipus que estan fets en vidre funcionen millor que els altres
- a més això fa que siguin més transparents
- no cal calibrar-los més d’una vegada
- poden ser usades de qualsevol manera: dit, guants, stylus, etc.
Capacitive
- llarga duració
- bona relació qualitat preu
- inpermeable a la pluja i a la brutícia
- mides de 5.7″ a 32″
- sovint fabricats en vidre
- funcionen a través d’uns sensors que actuen com a capacitors
- les parets dels capacitors dels eixos horitzontals i els verticals es solapen
- aprofitant que el cos humà és conductor de l’electricitat, al tocar amb el dit la superficie del sensor el camp elèctric canvia i es produeix un canvi en la capacitància
- funcionen per proximitat, no cal arribar a tocar el tàctil
- tecnologia amb força durabilitat i que s’usa a força sistemes POS, industrials, kioskos públics, etc.
- és força més transparent que la tecnologia resistiva
- només funciona amb el contacte amb el dit, o amb stylus que siguin conductors
- suporten sistemes multi-touch
- una capa dura en el vidre proporciona resistència al desgast
- força resistent a la brutícia
- funciona força bé quan hem d’arrossegar elements en la interficie
- es considera que té un coeficient de transparència a la llum del ~91.5%
Infrared
- Ideal per entorns ostils i aplicacions a l’exterior
- Mides de 8.4″ a 17″
- usa una xarxa d’emisors d’infra-rojos basats en LEDs que estan repartits pels eixos horitzontals i verticals de la pantalla, a més d’uns fotosensors col·locats en els costats inversos dels emisors
- la idea és crear una xarxa de rajos infra-rojos i quan aquests es tallen ja tenim el toc
- no s’usa per elements portables només per instal·lacions fixes
- es pot usar amb el dit, guants, stylus, etc.
- és estable, no cal calibrar-la
- no té perquè treballar amb superficies fines, poden ser rugoses
- poden combinar-se fàcilment amb sistemes antivandàlics
- usades en estàndards Ingress Protection (IP) i NEMA
- durant molt
3M MicroTouchTM DST Touch System
- Superficies tàctils molt grans
- mides de 32″, 40″, 42″ i 46″
- vides tractats químicament
- no cal stylus per usar-la, funciona amb qualsevol objecte o element que toqui la pantalla
- resposta ràpida
- no són massa susceptibles a la brutícia
- 3M Dispersive Signal Technology (DST): bàsicament permet calcular les ondes de reflexió que es produeixen en el vidre tractat al haver-hi un toc
- Ràpid, precís i molt confiable
- Suporta esquerdes, rallades o fins hi tot objectes recolzats sobre la pantalla i continua funcionant amb precisió sobre les interaccions
- Idea per aplicacions multi-usuari
- Transparència excepcional
Cues del postfix i informacions relacionades
Per defecte les cues que té el postfix són:
- hold: missatges que no s’intenten entregar mai
- incoming: cua d’entrada de missatges
- active: cua en la que es decideix amb quin delivery agent s’itenta entregar un missatge
- defer/deferred: missatges que no s’han pogut entregar per un error temporal es posen en aquesta cua
- bounce: on es generen els missatges d’error cap al remitent dels missatges que no s’han pogut entregar
- corrupt: cua que conté missatges danyats amb els que no es pot fer res
Accions que podem fer amb els missatges d’una cua:
- Listing messages
- Deleting messages
- Holding messages
- Requeuing messages
- Displaying messages
- Flushing messages
Gestió de les cues:
- GUI per gestionar les cues de postfix
- Mostra l’estat de totes les cues.
mailq
- Mostrar els 10 dominis amb més missatges pendents d’enviar, sovint va bé per controlar quan ens han usat per fer un email i hi ha molts correus enganxats per enviar.
qshape -s deferred|head -n 10
- Borrar un missatge de les cues.
postsuper -d ID_MSG
- Borrar tots els missatges de les cues.
postsuper -d ALL
- Script per borrar missatges de les cues segons origen o destí:
#!/usr/bin/perl -w # # pfdel - deletes message containing specified address from # Postfix queue. Matches either sender or recipient address. # # Usage: pfdel # use strict; # Change these paths if necessary. my $LISTQ = "/usr/sbin/postqueue -p"; my $POSTSUPER = "/usr/sbin/postsuper"; my $email_addr = ""; my $qid = ""; my $euid =
gt;; if ( @ARGV != 1 ) { die "Usage: pfdel \n"; } else { $email_addr = $ARGV[0]; } if ( $euid != 0 ) { die "You must be root to delete queue files.\n"; } open(QUEUE, "$LISTQ |") || die "Can't get pipe to $LISTQ: $!\n"; my $entry = ; # skip single header line $/ = ""; # Rest of queue entries print on # multiple lines. while ( $entry = ) { if ( $entry =~ / $email_addr$/m ) { ($qid) = split(/\s+/, $entry, 2); $qid =~ s/[\*\!]//; next unless ($qid); # # Execute postsuper -d with the queue id. # postsuper provides feedback when it deletes # messages. Let its output go through. # if ( system($POSTSUPER, "-d", $qid) != 0 ) { # If postsuper has a problem, bail. die "Error executing $POSTSUPER: error " . "code " . ($?/256) . "\n"; } } } close(QUEUE); if (! $qid ) { die "No messages with the address <$email_addr> " . "found in queue.\n"; } exit 0;
- Borrar missatges segons email origen o destí.
/root/bin/pfdel email
- Hold a message / Retenir missatges, no intentar servir-los. Posar-los a una cua congelats.
postsuper -d ID_MSG
- Hold all messages
postsuper -d ALL
- Moure un missatge de la cua ‘hold’ a la cua ‘active’.
postsuper -H ID_MSG
- Moure tots els missatges de la cua ‘hold’ a la cua ‘active’.
postsuper -H ALL
- Re-encuar missatges, per exemple si el postfix tenia un erro de configuració després de corregir-los podem re-encuar els missatges perquè es corregeixin els possibles errors de classificació que hagin patit. Per exemple, canvi de ‘delivery agent’.
postsuper -r ID_MSG o postsuper -r ALL
- Veure el contingut d’un missatge que esta a la cua:
postcat -q ID_MSG
- Per forçar el re-enviament de missatges a la cua.
postqueue -s o postfix flush
- Per forçar l’enviament de missatges a la cua per un domini.
postqueue -s domini.com
Python: afegir suport de plug-ins al nostre codi
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.
- Paquet amb exemples: plugins.tar