Ordre a la llista!


Escrit per Aaloy a 23 de September , 2007 a les 7:18 p.m.

Una de les accions més repetitives que sovint feim quan passam cap a la capa de presentació és la d'ordenar els elements que volem que es presentin. Potser algú dirà que els elements ja poden venir ordenats de la consulta a la base de dades, però què passa si en lloc d'atacar a una base de dades directament obtenim el que s'ha de mostrar d'un servei web? o ja hem fet un tractament de les dades i ara les volem ordenar per un altra camp. Poder fer ordenacions de manera senzilla i ràpida ens soluciona molts maldecaps.

Anem a veure com Python ens permet fer ordenacions de llistes de pràcticament qualsevol cosa. Python fa servir el mètode sort per a ordenar una llista. L'exemple més senzill seria l'ordenació d'una llista d'enters

  $ llista = [2,4,5,6,7,6,7]
  $ llista.sort()
  $ llista
  [2, 4, 5, 6, 6, 7, 7]

Sí, és tan senzill com pareix, i fins i tot podem fer

  $ llista.reverse()
  $ llista
  [7, 7, 6, 6, 5, 4, 2]

Però clar, una llista a Python pot contenir qualsevol cosa, no sols sencers, anem a veure què passa si passam una llista de parells (tuples)

  $ llista = [(1,5),(1,2),(2,2),(3,5),(4,8),(1,9)]
  $ llista.sort()
  $ llista
  [(1, 2), (1, 5), (1, 9), (2, 2), (3, 5), (4, 8)]

Suposem però que jo el que vull és que s'ordeni pel segon element de la tupla, aquí si un prové d'altres llenguatges de programació ja se pot esperar tenir que escriure un bon munt de codi, però no en Python, l'ordenació es fa per una clau i podem definir quina és aquesta clau passant-li al mètode sort una funció construida de manera que prengui un sol element i ens retorni la clau a comparar.

Per fer el que volem farem servir el mòdul operator, i dins aquest la funció itemgetter, aquesta funció ens retorna una altra funció que aplicada damunt una llista o tupla ens donarà l'element especificat que haguem definit, així per exemple

  $ segon=itemgetter(1)
  $ segon(llista)
  (2, 2)
  $ llista
  [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]
  $ segon(llista)
  (2, 2)
  $ segon((1,5))
  5

Farem servir aquesta funció per a obtenir la clau per la qual volem ordenar la nostra llista, així

  $ llista.sort(key=segon)
  $ llista
  [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]

Pensem en les implicacions que té això quan volem omplir un select d'html, encara que la llista ens hagi arribada ordenada per codi, podem fàcilment canviar l'ordenació al texte sols amb aquesta instrucció. Un altra paràmetre que ens serà de molta utilitat a l'hora de fer ordenacions és el cmp, aquest ens permet passar una funció que donats dos arguments haurà de retornar un nombre positiu per indicar que el primer és major que el segon, zero per indicar que els elements són igual o negatiu per indicar que el segon és major que el primer.

Per exemple, suposem que el que volem fer és ordenar la nostra llista segons el que sumen els seus components.

   $ t=llista[:] #Farem primer una còpia de la llista original
   $ def ordena(x,y):
         p1 = x[0]+x[1]
         p2 = y[0]+y[1]
     return p1-p2
   $ t.sort(cmp=ordena)
   $ t
   [(1, 2), (2, 2), (1, 5), (3, 5), (1, 9), (4, 8)]
   $ llista
   [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]

O també poden fer un codi més florit i escriure

  $ t = llista[:]
  $ t
  [(1, 2), (2, 2), (1, 5), (3, 5), (4, 8), (1, 9)]
  $ t.sort(lambda x,y: x[0]+x[1]-y[0]-y[1])
  $ t
  [(1, 2), (2, 2), (1, 5), (3, 5), (1, 9), (4, 8)]

Si algú ha tingut la paciència d'arribar fins aquí, un momentet, que ara ve el més interessant. Què passa quan en lloc de llistes de nombres tenim llistes d'objectes? Doncs res, podem fer servir el paràmetre cmp o el paràmetre key segons ens vagi millor per fer l'ordenació. Anem a veure tres maneres de fer el mateix. Primer definirem la nostra llista d'objectes

   class Persona:
       def __init__(self, nom, edat):
           self.nom = nom
           self.edat = edat
       def __cmp__(self, altri):
           return cmp(self.edat,altri.edat)

Aquí el que he defint és una funció cmp dins la classe, que és la que faríem servir per defecte a l'hora d'ordenar una llista d'objectes d'aquest tipus, així:

    $ agenda = [Persona('Benjamí', 31), Persona('Pau', 22),  
      Persona('Juan',34), Persona('Ricardo',38), 
      Persona('Guillem',28), 
      Persona('Bernat',58)]
    $ agenda.sort()
    $ for amic in agenda:
    $   print "%25s \t %i" % (amic.nom, amic.edat)
            Pau            22
            Guillem        28
            Benjamí        31
            Juan           34
            Ricardo        38
            Bernat        58

Ara suposem però que volem ordenar la llista per nom. Una opció seria refer el mètode cmp, però tenim altres opcions. La primera és encriure una nova funció de comparació:

  $ def compara_nom(amic1, amic2):
  $    return cmp(amic1.nom,amic2.nom)
  $ agenda.sort(compara_nom)
  $ for amic in agenda:
  $     print "%25s \t %i" % (amic.nom, amic.edat)
                  Benjamí        31
                   Bernat        58
                  Guillem        28
                     Juan        34
                      Pau        22
                  Ricardo        38

O bé, si ens agrada més l'opció lambda

 $ agenda.sort(lambda amic1, amic2: cmp(amic1.nom,amic2.nom))

Però encara tenim una altra maner, deixant que Python faci la feina per nosaltres, hem d'indicar la clau d'ordenació i fer que les eines de comparació del llenguatge facin la seva via. El problema però està en com dir-li quina clau fer servir, això s'aconsegueix amb attrgetter de la llibreria operator.

 $ agenda.sort(key=attrgetter('nom'))
 $ for amic in agenda:
 $     print "%25s \t %i" % (amic.nom, amic.edat)

Fixau-vos el senzill que seria poder fer una ordenació per qualsevol camp de la classe.

Referències:


Traducciones/Translations by apertium

1 comentari, 0 trackbacks (URL) , Tags: Python


Cap a una nova arquitectura de desenvolupament


Escrit per Aaloy a 15 de September , 2007 a les 11:46 a.m.

En el negoci on-line cada cop és més important adaptar-se als canvis més ràpid, posar nous serveis a l'abast dels clients i fer-ho per ahir. Fins ara havíem fet servir dues aproximacions diferents:

  • aplicacions fetes en Python i Django, per les parts més dinàmiques i mensy crítiques del negoci
  • aplicacions desenvolupades anb Java/J2EE de contenidor fi (Tomcat) per les parts més serioses del negoci.

Llevat de la conya de que Java deixa més tranquils a consultors i auditors, he de dir que la tecnologia té moltes coses bones, la qualitat del programari obert és molt bona, i bastiments com XFire (ara baix l'ala del projecte Apache), Spring o Hibernate fan la vida del programador molt més senzilla, encara que la corba d'aprenentatge sigui gran. La tecnologia està té un gran nombre d'eines i els IDE de desenvolupament com Eclipse o Netbeans són vertaderes meravelles.

El problema fonamental que té fer-ho tot en Java és que és força lent fer el desplegament de les aplicacions, així com fer petits canvis en la lògica de negoci o la capa de presentació. Fer un canvi que afecti a la part del model implica sovint tenir que recarregar l'aplicació a Tomcat, maleir quan a la sessió de depuració veus que no t'ha refrescat les classes, reiniciar el contenidor, esperar fins a un minut o dos que recarregui tot i començar la depuració.

La posada en producció també es veu afectada per com fa les coses la tecnologia, la velocitat i l'estabilitat que dona Java i el Tomcat s'aconsegueixen fent que les aplicacions es despleguin al contenidor, que la capa de presentació es compili en temps d'execució. La qual cosa vol dir, que un desplegament típic de les aplicacions pot dur un mínim d'uns 15 minuts entre baixar el servidor, posar-hi l'aplicació, pujar el servidor i fer que aquest compili els jsp. Baixar el servidor no vol dir aturar-ho, sinó llevar-ho de l'accés públic, encara que sovint aquest llevar-ho de l'accés públic també implica l'aturada.

Davant això tenim aplicacions fetes amb Django i Python, on provar un canvi no duu més que uns pocs segons, el servidor de desenvolupament respon de manera immediata als canvis fets en el codi. Posar una aplicació a l'entorn de proves normalment implica actualitzar el repositori de subversion al tag que s'hagi determinat com estable i fer un reload de l'Apache, tot plegat menys de 15 segons. Passar-ho a producció normalment és igual de senzill, moltes vegades ni tan sols és necessari establir un procediment d'aturada del servei, ja que l'actualització de les plantilles no implica aturada i un reload de l'Apache no arriba al segon en els mega servidors de producció.

Hem d'aconseguir anar cap a una arquitectura d'aplicacions i de desenvolupament que aconsegueixi unificar el millor dels dos mons: la facilitat de desenvolupar i testejar aplicacions sense capa de presentació que té Java i la potència i facilitat de fer canvis a la capa de presentació de Python i Django.

En altres apunts ja he comentat cap a on volia anar, fer els serveis en Java, que se n'encarregaran d'accedir a les bases de dades i fer tota la fontaneria necessària i fer tota la capa de presentació web en un llenguatge dinàmic, en el nostre cas Python amb el bastiment Django, que sigui un consumidor dels serveis web.

Amb això podem no tant sols escalar les aplicacions, sinó també escalar l'equip de desenvolupament, ja que podem tenir equips fent feina a cada una de les capes de l'aplicació sense que hi hagi pràcticament interferències una vegada s'han definits els serveis.

Donat que els serveis no tenen capa de presentació i per tant no hi ha compilacions de JSP per exemple, resulta que el temps necessari per desplegar-los és molt petit comparat amb de l'aplicació sencera. El testeig es relativament senzill, bé amb tests d'unitat direcatament en Java o amb eines com SoapUI.

Ens queda doncs lligar la capa de serveis (arquitectura SOA que queda millor), amb la capa de presentació. Consumir serveis web Soap complexes amb Python fins ara no era senzill, l'espacificació Soap és tan complexe que llevat de el propi Java i .net (a la seva manera), són capaços de convertir el wsdl publicat a classes manejables pel programador. Però això està canviant i ho està fent molt ràpid, el projecte ZSI ha madurat molt els darrers temps i a les darreres proves ha demostrat que és capaç de consumir els serveis web fets amb XFire sense problemes. També hi ha que dir que els serveis ja s'han pensat de tal manera que siguin fàcils de mapejar, evintat fer us de característiques sols suportades sols per Java, però això no crec que sigui una mancança sinó una inversió de futur, augmentar la complexitat implica augmentar també temps de depuració i tenir que lluitar amb incompatibilitats entre versions.

Els prototips realitzats fins al moment són molt encoratjadors, els temps de resposta de tot plegat és excel·lent, sense fer optimitzacions tenim temps de 0.6s des de la capa de presentació feta amb Python fins a la capa de base de dades a la que s'hi ha accedit mitjançant un servei web fet amb Java i XFire.

Encara que hi ha una regla que diu que quan es fa un estudi per veure la viabilitat d'un projecte aquest estudi sempre dóna que és viable, per ara tot pareix demostrar que el camí pel que estam anant és correcte i que per projectes amb molts programadors és molt productiu, ja que a més de separar l'aplicació en capes, estam separant en capes el propi desenvolupament.

Queden encara força aspectes a estudiar, però que no són tant d'arquitectura d'aplicacions com de metodologia de desenvolupament i de desplegament de les aplicacions, de manera que s'acabin optimitzant tant els mètodes de desenvolupament, el mètodes de desplegament com la comunicació entre els membres del projecte. L'objectiu és poder respondre ràpid a les necessitats del negoci i que la tecnologia no ens condicioni de manera negativa el temps de resposta, mantenint al mateix temps l'estabilitat i l'escalabilitat de les aplicacions.

Hi som molt aprop....!


Traducciones/Translations by apertium

0 comentaris, 0 trackbacks (URL)


Creant objectes a la manera de Python.


Escrit per Aaloy a 09 de September , 2007 a les 10:33 p.m.

He estat mirant coses damunt patrons de disseny aplicables al model d'interfície gruixuda d'usuari, aplicables a la programació amb wxPython, arribant a tres patrons:
  • El patró MVC (Model view controller) de sobres conegut per la gent que es dedica al desenvolupament web fonamentalment.
  • El patró MVP (Model view presenter) , que intenta fer que la part d'interacció sigui més testejable y que Flower ha considerat que s'havia de xapar en dos.
  • El patró Presentació Model, que independitza la capa de presentació de la vista, en un intent de separar el que és la part de comportament i estat de la vista en un model que és part de la presentació però que no es específic d'una implementació d'interfície concreta.
Llegint el codi he arribat una manera de construir objectes a partir de llistes que no havia fet servir fins ara. Això s'explica millor amb un exemple: class Agenda: ... def __init__(self, nom, llinatge, telefon, amic=True): ... self.nom = nom ... self.llinatge = llinatge ... self.telefon = telefon ... self.amic = amic ... La manera habitual de crear un objecte de tipus Agenda seria per exemple amic = Agenda('toni','aloy','971xxxxxxx') Suposem ara que tenim la informació dins una llista o una tupla, bastant habitual si per exemple hem importat les dades d'un arxiu de text o des de una base de dades, aleshores podem tenir la informació com un_amic =('Pau','Rul·lan','971xxxxxxx') La creació de l'objecte és molt ràpida d'escriure amic2 = Agenda(*un_amic) amic2.nom 'Pau' És a dir, s'han substituït els paràmetres de construcció de l'objecte pels valors de la llista. Aquesta substitució és posicional, és a dir, el primer valor correspon al primer paràmetre, el segon al segon, etc. La sintaxi és conseqüent amb la manera d'anomenar llistes de paràmetres en la construcció de funcions, per exemple: def prova (x, *y): ... print x ... for item in y: ... print item ... prova(2,3,4,5,6,7) 2 3 4 5 6 7 prova (2,7,10) 2 7 10 Però clar, si això funciona d'aquesta manera i estam parlant de Python i haurà una manera obvia de fer el mateix si en lloc d'una llista tenim un diccionari, és a dir, ara tenim: un_amic ={'nom':'Benjamí','llinatge':'Villoslada','telefon':'971xxxxxxx'} Les claus del diccionari coincideixen amb els noms dels paràmetres, i hauríem de poder fer amic3 = Agenda(**un_amic) Això és Python, i per tant amic3.nom 'Benjam\xc3\xad'

Traducciones/Translations by apertium

3 comentaris, 0 trackbacks (URL) , Tags: Python


Llegir codi


Escrit per Aaloy a 09 de September , 2007 a les 1:36 p.m.

Aquests darrers dies estic llegint el llibre wxPython in Action de Robin Dunn i Noel Rappin. El llibre és un tutorial de com escriure aplicacions fent servir la llibreria wxPython i com fer servir cada component (widget) que la llibreria inclou.

En el que és la explicació de cada component i els exemples hi ha una gran quantitat de llistats de codi font i comentaris damunt aquests llistats. Això m'ha fet recordar el capítol en que Glass tracta la importància de poder llegir codi. Diu, i estic completament d'acord, que a programar no se n'aprèn sols coneixent la sintaxi del llenguatge de programació, sinó també escrivint programes i sobretot llegint codi que ha escrit altra gent, i que aquesta capacitat de llegir codi s'hauria de cultivar més a les universitats i escoles tècniques.

Sense aquesta capacitat de llegir codi d'altres també ens trobam que llegir tutorials com el de wxPython es fa pràcticament impossible, si no som capaços de llegir el codi, interpretar mentalment que fa i imaginar-nos la sortida, no ens queda més remei que picar el codi i executar-ho per aprendre, la qual cosa fa que l'avanç en el domini de la llibreria sigui molt més lent.

Ser capaç de llegir el codi d'un altre ens permet aprendre noves tècniques que potser no estan explicades en el llibre, normalment perquè no és el seu objectiu, i ens permet la lectura a llocs allunyats de l'ordinador: al sofà, a la fresca a la terrassa,...

El programari lliure ens permet llegir codi que ha fet altre gent, veure com funciona, aprendre noves tècniques o veure el que s'ha fet malament o maneres de millorar-ho. Aquesta capacitat és fonamental a l'hora d'aprendre el funcionament d'una nova llibreria, de fer inspeccions de codi abans de posar en test un programa, o a l'hora de depurar o modificar codi que ha fet una altra persona.

Les èpoques del programador solitari que ho feia tot han ja queden lluny. El més normal actualment és que els programes és desenvolupin en equip i la gent acostumada a llegir codi ho té molt més fàcil per a adaptar-se a la feina en equip.

Si una persona sols ha fet feina fent servir programari tancat no haurà tingut l'oportunitat d'aprendre el que significa poder veure codi de tercers i per tant la seva evolució com a programador serà menor que aquells que estan acostumats, bé per necessitat o bé per convicció, a llegir el codi font d'altres persones.

Com vaig sentir a dir a Ricardo Gali a una conferència de Bulma, el codi és una font en sí mateixa per emmagatzemar i transmetre coneixement.En els cas dels programadors això també es tradueix en possibilitat d'aprenentatge i amb minimitzar el nombre d'errors i tasques de depuració.


Traducciones/Translations by apertium

1 comentari, 0 trackbacks (URL) , Tags: Llibres i revistes Gestió de projectes


L’akismet, que filtra massa


Escrit per Aaloy a 04 de September , 2007 a les 9:31 p.m.

Arrell d'un comentari de Paco Ros me n'he adonat que l'Akismet m'està filtrant comentaris que realment no són spam. El truc de Paco ha estat bo, posar un comentari a un altre article prou simple per a que passàs el filtre i avisar del que passava. Si a algú no ha vist els seus comentaris al bloc em sap greu. Tenc configurat el Wordpress per a que no moderi els comentaris una vegada ja s'ha fet el primer, però no em pesava que després passarien per l'Akismet i no l'he anat revisant. Serà cosa de fer-ho periòdicament, però si veis que els vostres comentaris no apareixen, doncs aplicau el truc de Paco :)

Traducciones/Translations by apertium

0 comentaris, 0 trackbacks (URL)


Facts and Fallacies on Sofware Engineering


Escrit per Aaloy a 04 de September , 2007 a les 6:15 p.m.

Facts and Fallacies of Sofware Engineering Robert L. Glass Ed. Addison-Wesley ISBN 0-321-11742-5 He devorat aquest llibre. Fins i tot quan ja no podia més de son una de les darreres coses que he fet aquests dies és anar llegint un dels fets o fal·làcies que ens presenta Glass. L'estructura de com se presenta el llibre és molt interessant: presenta els fets, després en diu si hi ha opinions contràries i finalment cita les fonts i les referències bibliogràfiques. Aquestes darreres serveixen molt per aprofundir en el tema, per exemple que la tècnica de la inspecció de codi és bona per a detectar errors no és res nou (encara que hauríem de veure a quantes empreses es fa o estaria ben vist que es fes), però que la seva eficàcia arribi a poder detectar el 90% d'errors fa que la vegi d'una altra manera, i que per tant tengui moltes més ganes de saber-ne més. La bibliografia que adjunta Glass de bon segur que formarà part de la meva propera llista de la compra a Amazon. També crec que és molt interessant com a lectura per als que creuen que hi ha bales de plata o que la informàtica és una ciència ben formalitzada. Per cert, a la bibliografia de l'autor diu que fa més de 45 anys que exerceix la professió, des del 1954, supòs que no hi havia titulacions informàtiques aleshores, segons alguns això del descartaria per poder fer feina a Espanya. Ho sent-ho, no me n'he pogut estar, però això està també dins l'esperit del llibre: el fer pensar, raonar, ... Glass ens amolla les idees per a que hi pensem, ens diu que hi podem estar d'acord o no, però que ell ho veu així i aporta referències i estudis per argumentar les seves tesis. Puntuació? Totalment recomanable.

Traducciones/Translations by apertium

3 comentaris, 0 trackbacks (URL) , Tags: Informàtica Llibres i revistes


Intrussisme professional a la informàtica


Escrit per Aaloy a 03 de September , 2007 a les 7:26 p.m.

Aquests dies he estat força entretingut llegint els articles d'En Ricardo damunt el tema de la regulació de la carrera informàtica i la necessita de crear un col·legi professional que lluiti contra l'intrussisme laboral per la via d'obtenció de privilegis. Personalment comparteixo la postura de Ricardo. No entenc què és vol regular d'una professió com la informàtica i la programació on no queda clar què hi ha d'art i què hi ha de ciència. Però és més, d'una tacada es vol deixar fora de la professió a tot un conjunt de gent, físics, matemàtics, emprenedors, que han inventat la informàtica tal i com la coneixem avui en dia. No oblidem que la programació es pot considerar com una matèria instrumental, que s'ensenya com se poden ensenyar les matemàtiques a físiques, i com a tal es perfectament possible que molta gent amb una formació científica sigui tan bona programant com qualsevol enginyer informàtic. La frontera entre el que pot fer un o altre no la marca la titulació, sinó l'empresa, ja sigui pública o privada. En el primer cas es solen requerir titulacions compatibles i passar unes oposicions, en la part privada, cada empresa sap el que li convé. Això vol dir que la titulació no val res? No seré jo qui ho digui. La titulació estableix un punt de partida, serveix d'entrada per suposar que es tenen uns coneixements mínims i una base, però no signifiquen que després un hagi de ser un bon professional.  En el cas de la informàtica on els coneixements es queden obsolets ràpidament, el més important per a un professional és la formació contínua, formar-se i preparar-se per tal de no esdevenir obsolet. En aquesta preparació tenir els coneixements que ens dóna la carrera en serveix per fer que la corba d'aprenentatge sigui molt més suau. Aquesta idea és la que defensa sovint la gent docent, que la universitat no ha d'ensenyar a fer anar un programa concret, sinó que ha d'ensenyar els conceptes i preparar a la gent per poder afrontar amb garanties el seu futur professional. Per una altra banda, voler una regulació implica no ser massa conscients del que representa programar. Segons Brooks és la tasca més complexa que mai ha fet l'home, i hi estic totalment d'acord. Els disclaimers que acompanyen als programes són necessaris per deixar ben clar que no es pot garantir que el programa funcioni, hi ha massa factors que hi intervenen: la programació, el maquinari, la gent que el fa servir i l'ús que en fa aquesta gent en són uns quants. En aquests moments no crec que cap asseguradora fos capaç de vendre'ns una assegurança col·lectiva que ens protegís de reclamacions per fallades de programari. Si fos possible crec que tothom ens hi apuntaríem, sols per ser els primers en poder reclamar i cobrar les primes. Voler regular la professió implica dir que som millors, que els nostres programes estan més ben fets que els que pugin fer físics, químics, telecos, matemàtics i en definitiva qualsevol que estigui fent ús de la informàtica com a eina en la seva professió,  sense poder demostrar que això és així i traint l'esperit dels que ens han duit fins aquí. La carrera informàtica és molt jove, i convé que recordi que no fa massa anys les principals empreses contractaven no informàtics, sinó matemàtics i físics, perquè normalment havien programat molt més que el recents sortits d'una carrera d'informàtica encara sense definir del tot i estaven molt més preparats pel raonament i el cercar-se la vida. Perquè veient alguns comentaris que li han fet a Ricardo pens que a la part del raonament encara li queda molt. Afortunadament la majoria d'informàtics no som així. Al manco jo tenc ben clar que la informàtica tal com està avui en dia no es pot considerar del tot una ciència, encara li queda molt camí per recorre. Avui llegia un estudi que deia que sols el 15% de les publicacions informàtiques són estudis amb dades i xifres raonades, front a 60 ó 70% d'altres ciències. Crec que la xifra no és anecdòtica. Basta anar a cercar ratios de productivitat per llenguatge, sistemes d'estimació de costs o mètriques de programació per adonar-nos que encara estam lluny del que han assolit altres enginyeries, i potser no ho assolirem mai, però això és el gran repte que tenim com a informàtics i la grandesa dels temps que estam vivint. Potser seria bo que els col·legis existissin, però no per reclamar privilegis sinó per ajudar a convertir la informàtica amb una vertadera ciència, fomentant la investigació pura, exigint que el codi, que és la nostra font principal de coneixement, sigui lliure, que les administracions obrin els seus projectes i les seves dades per tal que es puguin tenir mètriques i estudis que ens ajudin a tenir dades estadístiques que ens ajudin en les nostres tasques diàries. I si aquesta ajuda ve d'enginyers informàtics, matemàtics, físics o de professors de llatí,...  és del tot irrellevant.

Traducciones/Translations by apertium

3 comentaris, 0 trackbacks (URL) , Tags: Informàtica