Cosica

Después de ver tanto tiempo Muchachada Nui, quería probarme para ver si era capaz de hacer algún sonido parecido al que ellos hacen con vocoders. El resultado es este:





Esta hecho con cubase a partir de un audio (mi voz) + vocoder del propio programa.

Publicado porDaNieLooP en 12:12 PM 0 comentarios  

Haskell, sudokus, sequías y más pamplinas

Hace milenios que no actualizo el blog, y no es por falta de ganas, de momento estoy haciendo las gestiones con dios para que la Tierra gire mas lentamente y los días duren más. Espero que con esto los que habeis insistido en que actualice podais aguantar un poco (ya sé que mis entradas son de imprescindible lectura y de un valor literario incalculable).
Y creo que voy a hacer un popurri de las cosas que me han ido viniendo a la mente durante la ducha, en la que he intentado pensar el tema de la actualización.
Bueno, comencemos pues. Hará unos 3 años tuve una asignatura en la carrera un tanto exótica: programación funcional. En mi facultad al menos estamos bastante acostumbrados a lenguajes como C o Java, todos englobados dentro de la programación imperativa (cuando compilas código, dentro de la máquina hay unos enanos fustigados por un enano más grande que les manda). Pero llegamos a 3º y podemos deleitarnos con maravillas como Haskell, algo totalmente distinto a lo que estamos acostumbrados, donde aparecen términos tan fascinantes como "evaluación perezosa" o "listas intensionales".
No voy a entrar en detalles, pero se pueden hacer maravillas como crear listas infinitas (por ejemplo podríamos definir una lista con TODOS los números primos, una lista en la que que al interpretar el código irán apareciendo por orden todos los números primos (obviamente cuando hay una cantidad considerable de ellos, la velocidad a la que aparecen nuevos primos va disminuyendo...).
Tampoco quiero que penseis que Haskell es EL lenguaje, tiene sus usos, pero mas bien científicos (aunque existe una versión de quake en haskell).
Bueno, durante el transcurso de la asignatura tuvimos la ocasión de escribir algún programa, y yo elegí hacer un resolutor de sudokus (tonto de mí).
Para una mente que piensa en imperativo, escribir algo en funcional es algo tremendamente complicado. Sobre todo porque no podemos hacer uso de nuestros amigos los bucles iterativos. En Haskell tooodo es recursión.
Una vez superados estos problemas (y sin conocimientos aún sobre la transformación de programas iterativos a recursivos) escribí un churro que finalmente resolvía sudokus, no demasiado eficiente (hace una búsqueda en el espacio de estados en anchura), pero oye funcionaba, y los programas son como hijos, que aunque te salgan feos o tontos los quieres igual.
Estos programillas se podían entregar al profesor para ver si subía algo la nota final, y bueno, anonadado me quedé con la respuesta del profesor:

Muchas gracias. Viendo el código pensé que sería bastante más ineficiente, pero parece que no va tan mal.

Un saludo

He de decir que ahora que estoy más acostumbrado al contacto con profesores por e-mail, no me resulta tan extraña la respuesta, pero es cuanto menos curiosa.
Os pongo mi churro de programa aquí para que veais a mi hijo tonto (perdón, programa):

----------------------------------------------------------------------------------
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.

-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.

-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see .
----------------------------------------------------------------------------------
-- SIMPLE SUDOKU author: Daniel Tabas Madrid danieloop@gmail.com
----------------------------------------------------------------------------------
-- EJEMPLOS DE SUDOKUS

--Para introducir los sudokus incompletos dentro de la función he optado por ponerlos como listas
--de enteros. También pense en ponerlos como listas de listas, con 9 listas con 9 enteros cada una,
--pero opté por listas simples porque para calcular las coordenadas de cada posición no me hizo falta
--tener la referencia de una lista por fila, o columna. Los ceros representan los huecos dentro del
--Sudoku.

--Sudoku 1
s1::[Int]
s1=[0, 0, 7, 0, 0, 0, 0, 0, 2,
0, 1, 0, 8, 0, 4, 7, 0, 0,
0, 8, 0, 2, 0, 0, 0, 3, 6,
0, 0, 3, 0, 0, 7, 0, 5, 8,
0, 4, 8, 0, 0, 0, 1, 6, 0,
1, 7, 0, 5, 0, 0, 3, 0, 0,
7, 5, 0, 0, 0, 8, 0, 4, 0,
0, 0, 6, 4, 0, 9, 0, 7, 0,
2, 0, 0, 0, 0, 0, 6, 0, 0]

--Sudoku 2
s2::[Int]
s2=[0, 5, 0, 0, 0, 1, 6, 0, 0,
3, 0, 6, 0, 0, 0, 0, 0, 0,
0, 0, 9, 3, 0, 0, 2, 0, 4,
0, 0, 0, 0, 3, 0, 1, 0, 2,
0, 0, 0, 8, 0, 4, 0, 0, 0,
8, 0, 5, 0, 2, 0, 0, 0, 0,
6, 0, 1, 0, 0, 5, 3, 0, 0,
0, 0, 0, 0, 0, 0, 9, 0, 1,
0, 0, 7, 2, 0, 0, 0, 4, 0]

--Sudoku 3
s3::[Int]
s3=[0, 0, 0, 0, 8, 1, 4, 5, 7,
0, 1, 9, 5, 2, 7, 3, 8, 0,
7, 0, 5, 0, 0, 0, 0, 0, 0,
6, 0, 7, 0, 0, 0, 5, 2, 0,
5, 2, 1, 6, 0, 4, 8, 3, 9,
0, 9, 0, 2, 3, 5, 6, 7, 0,
2, 5, 0, 0, 0, 6, 0, 0, 8,
0, 0, 8, 0, 4, 0, 1, 6, 0,
1, 4, 6, 0, 5, 8, 0, 0, 3]

--Sudoku 4
s4::[Int]
s4=[0, 1, 5, 4, 2, 7, 9, 3, 8,
4, 0, 7, 3, 5, 9, 6, 2, 1,
9, 3, 0, 6, 8, 1, 5, 7, 4,
7, 5, 8, 0, 4, 3, 1, 6, 2,
3, 2, 9, 5, 0, 6, 4, 8, 0,
1, 6, 4, 2, 7, 0, 3, 5, 9,
2, 9, 1, 7, 6, 5, 0, 4, 3,
5, 7, 3, 8, 9, 4, 2, 0, 6,
8, 4, 6, 1, 3, 2, 7, 9, 0]

--Sudoku 5
s5::[Int]
s5=[0, 5, 0, 0, 6, 0, 0, 0, 1,
0, 0, 4, 8, 0, 0, 0, 7, 0,
8, 0, 0, 0, 0, 0, 0, 5, 2,
2, 0, 0, 0, 5, 7, 0, 3, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 0, 6, 9, 0, 0, 0, 5,
7, 9, 0, 0, 0, 0, 0, 0, 8,
0, 1, 0, 0, 0, 6, 5, 0, 0,
5, 0, 0, 0, 3, 0, 0, 6, 0]

--Sudoku 6
s6::[Int]
s6=[0, 2, 4, 0, 1, 0, 0, 0, 0,
0, 7, 0, 0, 3, 0, 0, 0, 9,
1, 0, 0, 0, 0, 7, 0, 0, 4,
5, 3, 9, 0, 0, 0, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0, 6,
0, 0, 0, 0, 0, 0, 9, 5, 3,
6, 0, 0, 4, 0, 0, 0, 0, 1,
9, 0, 0, 0, 2, 0, 0, 4, 0,
0, 0, 0, 0, 5, 0, 7, 3, 0]
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
--Funciones que he utilizado para crear coordenadas y utilizarlas dentro del sudoku, y para eliminarlas
--cuando ya no hacen falta.
-----------------------------------------------------------------------------------

--Función en la que se introduce una lista de enteros y una lista de coordenadas de 2 dimensiones
--formada por una tupla de enteros, y devuelve una lista de tuplas con la unión de las dos listas
-- utilizando la función predefinida zip
gencoord::[Int]->[(Int,Int)]->[(Int,(Int,Int))]
gencoord [] [] = []
gencoord xs ys = zip xs ys

--Función que utilizando la función gencoord mezcla una lista de enteros con coordenadas, para crear
--las coordenadas con las que trabajaré para resolver el sudoku. Las coordenadas las he creado con una
--lista intensional.
meteCoord::[Int]->[(Int,(Int,Int))]
meteCoord xs = gencoord xs [(x,y)|x<-[1..9],y<-[1..9]]

--Función en la que se introduce una tupla de dos elementos y devuelve el primero. La he utilizado para
--quitar las coordenadas después de resolver el sudoku.
first::(a,b)->a
first(a,b)=a

--Función en la que se introduce una lista de tuplas con el primer elemento un entero y el segundo una
--tupla de enteros que hacen de coordenadas, y devuelve una lista solo con los primeros elementos de las
--tuplas, para quitar las coordenadas después de resolver el sudoku.
quitaCoord::[(Int,(Int,Int))]->[Int]
quitaCoord xs= first (unzip xs)

----------------------------------------------------------------------------------
----------------------------------------------------------------------------------
--Funciones en las que miro la frecuencia de aparición de un número dentro de una casilla de sudoku
----------------------------------------------------------------------------------

--Función en la que se introduce el tipo del sudoku con coordenadas, y dos enteros con la coordenada
--de la fila y un número y devuelve un entero con el número de repeticiones del primer número dentro
--de la fila.
miraFila:: [(Int,(Int,Int))]->Int->Int->Int
miraFila [] a b = 0
miraFila ((a,(b,c)):xs) d e | b==d && a==e = 1 + miraFila xs d e
|otherwise = miraFila xs d e

--Función en la que se introduce el tipo del sudoku con coordenadas, y dos enteros con la coordenada
--de la columna y un número y devuelve un entero con el número de repeticiones del primer número dentro
--de la columna.
miraColumna:: [(Int,(Int,Int))]->Int->Int->Int
miraColumna [] a b = 0
miraColumna ((a,(b,c)):xs) d e | c==d && a==e = 1 + miraColumna xs d e
|otherwise = miraColumna xs d e

--Función en la que se introduce el tipo del sudoku con coordenadas, y tres enteros con las coordenadas
--de la fila y la columna y un número y devuelve un entero con el número de repeticiones del primer número dentro
--del bloque en el que estaban las coordenadas que se introducen.
miraBloque:: [(Int,(Int,Int))]->Int->Int->Int->Int
miraBloque [] a b c= 0
miraBloque ((a,(b,c)):xs) d e f | (div (b-1) 3)+1 == (div (d-1) 3)+1 && (div (c-1) 3)+1 == (div (e-1) 3)+1 && a==f = 1 + miraBloque xs d e f
|otherwise = miraBloque xs d e f

-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
--Funciones que he utilizado para realizar comprobaciones en el tablero al principio y durante la
--resolución del sudoku.
-----------------------------------------------------------------------------------

--Función en la que se pasa un tablero de sudoku con coordenadas, un número y unas coordenadas, y
--devuelve un booleano si la frecuencia de aparición dentro de fila, columna y bloque de ese número
--en esas coordenadas es 0 o 1. Se utiliza para luego comprobar si el tablero es correcto al inicio.
coordenadasCorrectoIni::[(Int,(Int,Int))]->Int->Int->Int->Bool
coordenadasCorrectoIni [] a b c= False
coordenadasCorrectoIni a b c d | (miraFila a b d) <=1 && (miraColumna a c d) <=1&& (miraBloque a b c d)<=1 = True
| otherwise = False

--Función que utiliza la función coordenadasCorrectoIni para comprobar si un tablero es correcto al inicio.
--Va realizando la función por todos los componentes del tablero y si encuentra un error devuelve False.
compruebaInicio::[(Int,(Int,Int))]->Bool
compruebaInicio [] = True
compruebaInicio ((a,(b,c)):xs) |a==0 = compruebaInicio xs
|a>0 && coordenadasCorrectoIni ((a,(b,c)):xs) b c a = compruebaInicio xs
|a>0 && (coordenadasCorrectoIni ((a,(b,c)):xs) b c a)==False = False

--Función que hace algo muy similar a coordenadasCorrectoIns, pero se utiliza a la hora de insertar un
--elemento, por lo tanto comprueba la frecuencia de aparición en esas coordenadas pero devuelve True
--sólo cuando la frecuencia es 0.
coordenadasCorrectoIns::[(Int,(Int,Int))]->Int->Int->Int->Bool
coordenadasCorrectoIns [] a b c= False
coordenadasCorrectoIns a b c d | (miraFila a b d) ==0 && (miraColumna a c d) ==0&& (miraBloque a b c d)==0 = True
| otherwise = False

--Función que comprueba si un tablero está completo, es decir, que no tiene
--ningún hueco (0) en el tablero.
compruebaFinal::[(Int,(Int,Int))]->Bool
compruebaFinal [] = True
compruebaFinal ((a,(b,c)):xs) |a==0 = False
|a>0 = compruebaFinal xs

------------------------------------------------------------------------------------
------------------------------------------------------------------------------------
--Funciones destinadas a la resolución del sudoku.
------------------------------------------------------------------------------------

--Función en la que se pasa por parámetro un tablero con coordenadas, un número y unas coordenadas,
--y devuelve el tablero con ese número insertado en esas coordenadas.
inserta::[(Int,(Int,Int))]->Int->Int->Int->[(Int,(Int,Int))]
inserta ((a,(b,c)):xs) x y n | b==x && c==y = ((n,(b,c)):xs)
|otherwise = (a,(b,c)):inserta xs x y n

--Función que devuelve la fila donde se encuentra el primer hueco del sudoku
fcoordPrimCero :: [(Int,(Int,Int))]->Int
fcoordPrimCero ((a,(b,c)):xs) | a==0 = b
| otherwise = fcoordPrimCero xs

--Función que devuelve la columna donde se encuentra el primer hueco del sudoku
ccoordPrimCero :: [(Int,(Int,Int))]->Int
ccoordPrimCero ((a,(b,c)):xs) | a==0 = c
| otherwise = ccoordPrimCero xs

--Función que toma un tablero de sudoku con sus coordenadas, busca la posición donde se encuentra
--el primer hueco, y crea una lista de tableros en la que cada tablero insertado contiene uno de
--los posibles números candidatos a ocupar el hueco que se ha buscado.
insertaCandidatos ::[(Int,(Int,Int))]->Int->[[(Int,(Int,Int))]]
insertaCandidatos [] c = []
insertaCandidatos a b | (coordenadasCorrectoIns a (fcoordPrimCero a) (ccoordPrimCero a) b) && (b<10) = [(inserta a (fcoordPrimCero a) (ccoordPrimCero a) b)] ++ insertaCandidatos a (b+1)
|(coordenadasCorrectoIns a (fcoordPrimCero a) (ccoordPrimCero a) b)==False && (b<10) = insertaCandidatos a (b+1)
|b==10 = []

--Función que devuelve el número de huecos que contiene el tablero.
nCeros::[(Int,(Int,Int))]->Int
nCeros [] = 0
nCeros ((a,(b,c)):xs) | a==0 = 1 + nCeros xs
| otherwise = nCeros xs

--Función que toma una lista de tableros y les va aplicando la función insertaCandidatos
--con lo cual se devuelve una lista de tableros después de haber insertado todas las posibles
--combinaciones de números a todos los tableros candidatos anteriores. Si un tablero de la lista
--de entrada no tiene ningún candidato posible, gracias a la función insertaCandidatos que en ese
--caso devuelve una lista vacía, es la forma en la que se va realizando la poda del "arbol" que
--se va generando.
pasoRecursivo:: [[(Int,(Int,Int))]]->[[(Int,(Int,Int))]]
pasoRecursivo [] = []
pasoRecursivo (x:xs) = insertaCandidatos x 1 ++ pasoRecursivo xs

--Esta función va realizando el paso recursivo tantas veces como le dicta el parámetro entero
--de entrada. El número de veces que se debería realizar la función viene determinada por
--el número de huecos que contiene el tablero al inicio.
resolucion:: [[(Int,(Int,Int))]]->Int->[[(Int,(Int,Int))]]
resolucion a b |b>1 =resolucion (pasoRecursivo a) (b-1)
|otherwise = pasoRecursivo a

--En esta función se introduce un tablero sin coordenadas, y se devuelve una lista de tableros
--con coordenadas con las soluciones del sudoku.
res:: [Int] -> [[(Int,(Int,Int))]]
res x = resolucion [(meteCoord x)] (nCeros (meteCoord x))

--Función que toma como entrada una lista de enteros que representa un tablero de sudoku, y devuelve
--la primera solución, comprobando que es correcta mediante el filter que se realiza.
resuelve::[Int]->[Int]
resuelve x = quitaCoord(head(filter (compruebaFinal) (res x)))

--------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------
-- Función principal
--------------------------------------------------------------------------------------
--Función que comprueba si el tablero es correcto al inicio, y si lo es, lo resuelve.
resuelveSudoku::[Int]->[Int]
resuelveSudoku x | compruebaInicio (meteCoord x) = resuelve x
| otherwise = error "el Sudoku inicial no es correcto y no puede tener solución"

Espero que a alguien alguna vez le sirva para algo (y no solo para copiarlo como práctica), es un churro bastante feo, la salida es una simple lista, pero como ya dije antes, funciona xD
Cuando tenga tiempo revisaré el código y lo intentaré mejorar (búsquedas en anchura para resolver sudokus, WTF).
Ah, y no os vais a librar, la próxima entrada podría tratar sobre CUDA y mi "fantabuloso" proyecto.

Publicado porDaNieLooP en 12:24 AM 6 comentarios  

Volver a la edad de piedra howto

Ayer volviendo en el metro a casa contemplé perplejo un atentado a los programadores de nokia: un "cani" sentado al lado mio se sacó un N70 y un N81, y se puso a pasar los teléfonos de uno a otro A MANO.
Nokia (al igual que otras muchas compañías que fabrican móviles) proporciona varios sistemas de traspaso de contactos de un móvil a otro, directamente por bluetooth, o creando una copia de seguridad en el ordenador y metiendosela al otro.
Pero no, este chico decidió pasar el telefono del Jonatan y de la Jeny a lo bruto. Bueno, unos pierden el tiempo así, y otros lo perdemos escribiendo tonteridas como estas...

Publicado porDaNieLooP en 6:19 PM 7 comentarios  

Necios en huelga?

Parece que vuelvo :)
En los últimos días ha habido bastante revuelo entre mis compañeros por una entrada en el blog de Ricardo Galli (recordemos que Galli es uno de los creadores de Menéame entre otras cosas).
No me parece muy digno de todo un profesor de universidad hablar como lo ha hecho este hombre, diciendo cosas como que todos los que opinen como el chico del video son unos iconoclastas del pupitre, o que le da grima que haya gente asi, que pobrecitos compañeros...
Mi intención con este post no es ni defender las atribuciones para los informáticos ni nada parecido. Simplemente me parece que criticar sin saber, desde una posición privilegiada, no es lo más apropiado. Es cierto que las declaraciones de un estudiante que no está todos los días hablando para los medios de comunicación pueden ser más o menos desafortunadas, y pueden ser fácilmente sacadas de contexto, pero en cierto modo no son tan erroneas.
Me explico: yo no soy defensor de las atribuciones como medio de regulación de una profesión. Pero también creo que ciertos profesionales parten con una situación de desventaja frente a otros, y con la que está cayendo, el miedo del mileurismo está ahí. Está claro que un buen profesional sabe que con sus conocimientos y su forma de trabajar no va a tener problemas para encontrar un trabajo que le satisfaga. Pero hablando de atribuciones y colegios y demás, también hay que tener en cuenta el negocio de algunos colegios que supuestamente están ahí para regular la profesión, y luego sirven para que los proyectos queden siempre en manos de los mismos enchufados...
Y cualquiera que lea esto dirá, oiga pues que se manifiesten para que quiten atribuciones al resto de carreras, no al revés. Sería lo ideal, sólo mantener una regulación en carreras como medicina, e implantar otro sistema para el resto, en el que se tengan en cuenta los conocimientos y la capacidad de trabajo y no el título (que por otra parte cuesta bastante sacar). Y ahí es donde entran en juego las empresas que por ahorrar costes, y al igual que una empresa de construcción para ahorrar costes puede comprar materiales de baja calidad que luego pasen factura a la calidad de lo construido, contratan a gente con pocos conocimientos. Y es que eso también pasa factura. Yo no digo que un ingeniero informático por el hecho de ser ingeniero va a hacer un software de calidad (que no sin fallos), pero tiene más posibilidades de hacerlo que una persona sin cualificación, ahí también entra en juego la curiosidad y el afán por aprender de cada uno.
Por lo tanto pedir atribuciones para una de las pocas ingenierías que no las tiene no me parece algo tan descabellado, que por cierto no es lo único que se ha pedido en estas manifestaciones, por si alguno no se ha enterado.

Publicado porDaNieLooP en 9:37 PM 2 comentarios  

Y más cambios...

No me terminaba de convencer la plantilla que había puesto, y la he vuelto a cambiar. Esta es lo más minimalista que he podido encontrar, fácil de leer, se ve todo muy ordenado... a lo mejor me entran ganas de escribir otra vez y todo.

Publicado porDaNieLooP en 2:47 PM 5 comentarios  

Cambios

Pues vaya, no se si os habreis dado cuenta (por los del google reader) pero he cambiado el diseño del blog. Contadme que os parece, si os gusta mas o menos que el anterior, si cambiariais la tipografia, los tamaños, etc etc.
En otro orden de cosas, mañana me matriculo del que, espero, sea el ultimo año de mi carrera. Ya os contare mis sensaciones cuando me matricule, si es que metanet me deja.

Publicado porDaNieLooP en 5:22 PM 8 comentarios  

El hombre que lo hace todo en España no la liaria parda...

Casi todos habreis visto a la socorrista toxica (que la ha liao parda):


A este hombre no le habria pasado:


Obviamente porque si es tantas cosas, tambien sera socorrista y quimico y sabra mezclar. De hecho hay un videoclip premonitorio sobre este hombre:


PD. Mi inspiracion hoy no da para mas, seguid votando para que me suicide, gracias a todos los que habeis marcado esa opcion.

Publicado porDaNieLooP en 12:18 PM 4 comentarios  

Y no importa...


Smashing Pumpkins. Que mas quieres que te diga?
Somos jovenes. Se nos acaba el verano. Para muchos pronto se nos termina una etapa. Pero no importa...

Publicado porDaNieLooP en 1:05 PM 0 comentarios  

Estadísticas

Hay cosas que no entiendo. He estado mirando las estadísticas de google analytics, donde tengo una media de 10 visitas por dia, y estos dias de atras tenia (oh lo siento ´´´´ me duele hasta a mi, es la Seta) 15-17 visitas diarias sin ninguna actualizacion. Ha sido actualizar y bajar el numero de visitas a 6.
Creo que voy a iniciar una encuesta por si quereis que cierre el blog (no lo voy a cerrar xD), pero los datos son inquietantes. Mas inquietante aun si cabe es que el 45% de las entradas vienen del buscador de google, buscando por las palabras clave: "peinado bakala malote kinki".
Estamos ante una generacion de internautas que quieren tener el pelo a lo cenicero? Cada vez creo menos en la humanidad...

Publicado porDaNieLooP en 12:20 PM 3 comentarios  

Una tras otra

Termino de comer y me encuentro con la noticia del accidente del avión en Barajas. Me ducho y voy a casa de MasterJ para darle pasta para un pedido de discos duros externos. Vamos a completar la compra y aparecen 14,92€ euros adicionales por disco. Con la $gae hemos topado!!! Mi compra pasa de 1TB a 0,5TB por no querer gastarme tanta pasta. Llego a mi casa y me mareo.
De verdad existe "dios"? Si existe se estara cachondeando de nosotros, y Ramoncin sera un angel vengador? Volvere a coger un avion despues de lo que ha pasado en Barajas?

Tantas y tantas preguntas, y ninguna respuesta (lo del canon tampoco tiene respuesa).

En fin, para la proxima ya se que tendre que comprarme un disco duro interno y una caja, y buscar un sitio donde no me cobren el canon (se supone que no pueden cobrarte canon en un disco que albergue el sistema operativo de un ordenador).

Publicado porDaNieLooP en 8:59 PM 4 comentarios