Renderizador de variantes varias de Mandelbrot
Pues eso, que he ampliado y traducido a C++ este script, debería ser bastante portable, todo es estándar (bueeeno, los pthreads...), lo único que me preocupan son las tuplas que tenían una ruta curiosa ¿? enfin, que debería funcionar bien, la memoria está bastante pulida y tal ( aunque todos sabemos como son estas cosas xD ).
Se puede descargar de este repo [ https://gitorious.org/rand/ff ], compila
con make
(en Unix debería detectar solo el número de núcleos, en todo caso
se puede especificar con -t <hilos>
), se pueden ver los parámetros con ./ff
-h
, ahora algunas pruebas con los modos nuevos... ( las 3 primeras están
rotadas 90 grados )
[caption id="attachment_920" align="aligncenter" width="580" caption="Buddhabrot: -a -i 1000 -m 100 -d 120 -r 10000000 -w 3000 -h 3000"][/ caption]
[caption id="attachment_921" align="aligncenter" width="580" caption="Anti buddhabrot: -aa -i 1000 -m 100 -d 120 -r 10000000 -w 3000 -h 3000"][/caption]
[caption id="attachment_922" align="aligncenter" width="580" caption="Buddhabrot Hologram: -ho -a -i 1000 -m 100 -r 100000000 -w 1200 - h 1200 -d 150"][/caption]
[caption id="attachment_926" align="aligncenter" width="600" caption="Julia basado en buddhabrot: -a -i 500 -m 100 -r 1000000 -j -1.1 0.1 -b"][/caption]
Y hay un par más subidas a deviantart ( de las que no recuerdo los parámetros :P )
http://kenkeiras.deviantart.com/art/Bodhi-bird-263712574
http://kenkeiras.deviantart.com/art/Anti-Buddhabrot-263741789
Eso es todo, hasta otra
[Referencias]
http://www.superliminal.com/fractals/bbrot/bbrot.htm
http://www.superliminal.com/fractals/bgram/bgram.html
Librería necesaria para instalar Freenet en Trisquel 5 [tip]
Después de 20 minutos buscando por qué fallaba ( no da error, solo no muestra el interfaz del instalador :P ), y antes de que le pase a alguien más: sudo apt-get install openjdk-6-jre
Ojalá todo fuera tan fácil de solucionar xD
Conocer en número de nucleos en Unix [C]
Muy rápidamente...
El número de nucleos de CPU se puede ver a través del directorio "/sys/ devices/system/cpu/", así que aprovechando que en Poesia_binaria_hay_un_post sobre_como_leer_directorios_en_C... aquí está un código que lee, la idea sería usar la función para usar el número correcto de hilos/procesos [getcpus.c]
include
include
include
include
define CPU_PATH "/sys/devices/system/cpu/"
int getCores(){
DIR *dir;
struct dirent* it;
int count = 0;
int i, isCpu;
dir = opendir(CPU_PATH);
if (dir == NULL){
exit(1);
}
while((it = readdir(dir)) != NULL){
if (strncmp(it->d_name, "cpu", 3) == 0){
isCpu = 1;
for(i = 3; it->d_name[i] != '\0'; i++){
if ((it->d_name[i] < '0')||(it->d_name[i] > '9')){
isCpu = 0;
break;
}
}
count += isCpu;
}
}
closedir(dir);
return count;
}
int main(int argc, char **argv){
printf("Encontrado(s): %i nucleo(s)\n", getCores());
return 0;
}
Hasta la próxima
Escribindo un parser de brainf*ck con BLK
Por fin! neste momento BLK pode compilar un subset razoable de C... ben, vale, restanlle os punteiros e as estructuras para ter algo decente, pero os primeiros son complicados de simular nun intérprete e as estructuras están en camiño. O importante é que a estructura xeral é relativamente estable, incluso dentro da rama de protipado, unha consecuencia é que está aberta a calquera participación :), así que vexamos un exemplo de como escribir un pequeno parser de brainf*ck.
O primeiro que faremos será importar o xestor do bytecode e preparar unha constante para soster o tamaño da memoria, que neste caso será unha constante
from bytecode_manager import *
MEM_SIZE = 1024
Encapsularemos o parser nunha clase coa seguinte forma
class BrainfuckParser:
code = "" # Unparsed code
_bytecode_manager = None # Bytecode manager
global_frame = None # The global function
Agora ven a función para iniciliza-la clase, recibe o xestor de bytecode como único parámetro
def init(self, bytecode_manager):
self._bytecode_manager = bytecode_manager
Agora temos que preparar un espazo para o código, este agrupase en frames (que veñen sendo como bloques de C, podendo representar funcións, bucles ou condicionais), polo menos fai falla un para que o código poda ser executado polo intérprete, chamemoslle '_start'
self.global_frame = gframe = bytecode_manager.add_function("_start", void_type, [])
A sintaxe é:
Bytecode_manager.add_function(
Alí dentro xa podemos definir variables e operacións, creemos manualmente unha variable cursor para almacenar a posición de memoria na que estamos, e asignemoslle o valor 0
bytecode_manager.add_variable("cursor", int_type, gframe, "Cursor variable")
bytecode_manager.add_op(ASSIGNATION_OP, {"name": "cursor"}, 0, gframe)
Aquí temos duas funcións novas, a primeira é Bytecode_manager.add_variable, recive como parámetro o nome da variable, o seu tipo, o frame e opcionalmente un comentario sobre a variable. Bytecode_manager.add_op añade unha operación o frame, o primeiro parámetro é o tipo de operación, o seguinte unha referencia a variable donde se gardará o resultado, despois os parámetros da función (sería unha lista se fora máis de un), e por último o frame
Tamén podemos crear un novo tipo para representar as nosas variables, por exemplo un array para a memoria, os tipos representanse coma diccionarios, necesariamente co atributo 'byte_size' que indica o tamaño en bytes que se adicarán, tamén hay outros atributos que poden usarse, como 'structure', que indica o tamaño das dimensions do tipo, por exemplo [2, 3] para un array de 2x3
tmp = {"byte-size": 4, "structure": [MEM_SIZE]}
bytecode_manager.add_variable("mem", tmp, gframe, "Machine memory")
O mesmo pasa coas referencias ás variables, se se indican cun diccionario podese especificar en 'pos' unha parte en concreto
def parse_brainfuck(self, frame):
pointed_ref = {"name":"mem", "pos": ["cursor"]}
cursor_ref = {"name":"cursor"}
O resto da función parse non necesita nada novo, só operacións ADD_OP e SUB_OP sobre as dúas referencias
while self.current < self.code_len:
current_op = self.code[self.current]
self.current += 1
# Print
if current_op == ".":
self._bytecode_manager.add_op("putchar", {}, [pointed_ref],
frame, ".")
# Read
elif current_op == ",":
self._bytecode_manager.add_op("getchar", pointed_ref, [],
frame, ",")
# Inc
elif current_op == "+":
self._bytecode_manager.add_op(ADD_OP, pointed_ref,
[pointed_ref, 1], frame, "+")
# Dec
elif current_op == "-": self._bytecode_manager.add_op(SUB_OP,
pointed_ref, [pointed_ref, 1], frame, "-")
# Push
elif current_op == ">":
self._bytecode_manager.add_op(ADD_OP, cursor_ref, [cursor_ref,
1], frame, ">")
# Pop
elif current_op == "<":
self._bytecode_manager.add_op(SUB_OP, cursor_ref, [cursor_ref,
1], frame, "<")
# While
elif current_op == "[":
b = self._bytecode_manager.add_branch(WHILE_BRANCH,
pointed_ref, frame)
self.parse_brainfuck(b)
# While-end
elif current_op == "]":
assert(frame != self.global_frame)
return
Para añadir control de fluxo utilizaremos Bytecode_manager.add_branch, pasándolle como primeiro parámetro o tipo de ramificación (WHILE_BRANCH, IF_BRANCH, ELSE_BRANCH ou DO_WHILE_BRANCH), o segundo parñametro é a condición, se é distinto de 0 executará o condicinal ou seguirá no bucle, o terceiro e o frame, ademais permite dous parámetros opcionais máis, o primeir indica as operacións que se executarán cada vez antes de comprobar o condicional, a outra, as que o farán antes de elas pero so a partir da segunda iteración
b = self._bytecode_manager.add_branch(WHILE_BRANCH, pointed_ref, frame)
O resto do código é suficientemente xenérico como para non necesitar casi ninguha explicación
def parse(self, f):
self.code = f.read()
self.current = 0
self.code_len = len(self.code)
self.parse_brainfuck(self.global_frame)
if name=="main":
output = "a.blk"
if len(argv) < 2:
print "%s " % argv[0]
exit(0)
try:
f = open(argv[1], "rt")
except:
print "Error reading %s" % argv[1]
else:
bm = BytecodeManager()
bm.add_entry_point("_start")
bfp = BrainfuckParser(bm)
try:
bfp.parse(f)
except ParsingException, e:
print "Parsing exception: %s" % e
exit(2)
bm.save(output)
O que si que é necesario mencionar é Bytecode_manager.add_entry_point que indica a función pola que entrar, e Bytecode_manager.save para garda-lo código
O código completo está aquí:
brainfuck_parser.py
Vémonos
Modificando `wardrive-android`
Bueno, pues aquí estamos, reestrenando blog :D
La aplicación Wardrive de android es una excelente herramienta para mapear redes con el móvil, que además está liberada bajo la licencia GNU GPLv3, en este post veremos como añadirle la opción de enviar la base de datos a un servidor web remoto.
Captura de la aplicación tomada del_repositorio
Lo primero que tenemos que hacer es descargar el código fuente, con svn checkout http://wardrive-android.googlecode.com/svn/trunk/ wardrive- android-read-only
Una vez hecho esto, lo abrimos con el IDE que prefiramos ( no me pararé a explicar como instalar los complementos para desarrollar para Android, se puede encontrar con una simple búsqueda ).
En el caso de NetBeans nos notificará que hay un problema, si hacemos click con el botón derecho en el proyecto y pulsamos en "Resolver problemas de referencia", dirá que '"Android_gapi_1.6" platform not found'. Si pulsamos en el botón resolver abrirá el gestor de plataformas, así que solo tenemos que seleccionar "Add platform".
El tipo de plataforma a instalar será "Google android ..."
A continuación tendremos que seleccionar la ruta al SDK
Y por último darle un nombre, "Android_gapi_1.6", y seleccionar la plataforma objetivo.
Una vez solucionados los problemas con el IDE, si no existe hay que crear un Dispositivo Android Virtual que incluya las API de Google, utilizadas para mostrar los mapas.
Ahora toca liarse con el código...
Primero añadiremos la opción de enviar los datos a la lista de opciones que
se accede a través del Menú > More. Este menú se encuentra en el
archivo options_menu.xml, en el directorio /res/menu , debajo de la siguiente
línea añadimos la misma modificada para nuestra opción:
El archivo quedaría por ejemplo así:
Además habría que añadir la cadena que tendría en cada idioma a los
archivos string.xml, aunque con añadirlo a la que se muestra por defecto es
suficiente en las pruebas dio problemas al añadirlo solo por defecto, aquí se
explica el paso para ponerlo en inglés. Podemos encontrar los valores en el
directorio /res/values-/ , buscamos la línea que contenga MENU_SEND_TO_WIGLE,
y la copiamos modificando los valores necesarios, es decir, añadimos esta
línea:
Hecho esto, ya se muestra la opción, aunque lo único que hace es mostrar el 'about':
Lo que queda por cambiar es la acción que se toma al pulsar el botón, esto se define en el case de la función onOptionsItemSelecteddel archivomain.java, bajo este switch: switch (item.getItemId())
Añadimos nuestro case: case R.menu_id.SEND_TO_SERVER:
showDialog(Constants.DIALOG_SERVER_UPLOAD);
break;
Bien, vamos entonces con el diálogo, al switch de la función protected Dialog onCreateDialog(int id) (~línea 625 ), hay que añadirle un nuevo case que tome la URL y nos la pase a una función para manejarla: case Constants.DIALOG_SERVER_UPLOAD:
builder = new AlertDialog.Builder(this);
final EditText URIinput = new EditText(this);
URIinput.setText("");
builder.setView(URIinput);
builder.setPositiveButton(getString(R.string.OK), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String uri = URIinput.getText().toString().trim();
send_to_server(uri);
}
});
builder.setNegativeButton(getString(R.string.NO),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
send_to_server(null);
}
});
return builder.create();
Lógicamente hay que añadir un valor DIALOG_SERVER_UPLOAD a la clase Constants en Constants.java, como public static final int DIALOG_SERVER_UPLOAD = DIALOG_WIGLE_UPLOAD + 1;
Además hay que importar android.widget.EditText, que se utiliza en el Dialog.
Todo lo que queda por escribir es la función send_to_server(), que hace return
si el string es null o envía el archivo a la url en un POST multipart,
nombrandolo como 'wardrive'.
public void send_to_server(String url){
if(url == null){
return;
}
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
File f = new File("/sdcard/wardrive.kml");
try {
MultipartEntity entity = new MultipartEntity();
entity.addPart("wardrive", new FileBody(f));
httppost.setEntity(entity);
httpclient.execute(httppost);
} catch (Exception e) {
}
}
Para esta función se requiere tener los .jar apache-mime4j, httpmime, httpclient y httpcore en el directorio de compilación e importar esto: import android.widget.EditText;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
Nota: lógicamente hay que exportar el KML antes de enviarlo al servidor
El código fuente resultante: wardrive-mod.zip
Y compilado: wardrive.apk
Y eso es todo, nos vemos. [Referencias] http://code.google.com/p/wardrive-android/ http://www.softwarepassion.com/android-series-get-post-and-multipart-post- requests/ https://code.google.com/p/androidmcr/source/browse/trunk/MCR/apache-mime4j- 0.6.jar?r=85 https://code.google.com/p/google-secure-data-connector/source/browse/trunk/ data-connector-agent/third-party/httpcomponents-client-4.0.1/httpmime- 4.0.1.jar?r=525
Como hacer las imagenes que ponen ip, navegador...
Para esto necesitaremos un servidor HTTP ( como apache ) y PHP, las dos cosas es lo tipico que se encuentra en un hosting gratuito ( aqui hay una lista )
Si lo vamos a alojar nosotros mismos necesitaremos habilitar el paquete php-gd para esto edita el php.ini, descomenta la linea de ";extension=php_gd2.dll" (quitale el ';'... en algunos casos es un '#') En debian/ubuntu se hace con "sudo apt-get install php5-gd"
Vamos alla...
Buscamos una imagen, la imagen sera la base, conviene que sea lo mas uniforme posible para que quede bien, yo escogí esta, aun que no sea la mas apropiada
Preparamos el codigo en PHP
El siguiente codigo es el que escribira en la imagen
Como funciona? (Para l@s que no les guste leer los comentarios del codigo)
Se usan dos funciones (navegador y os), que buscan en la cadena del "User- Agent", alguna parte conocida (Firefox, MSIE, etc...), y que devuelven el navegador y el sistema operativo del usuario
El resto es PHP,
$back="esfera.png"; //Imagen de fondo $img=imagecreatefrompng($back); //Se crea la imagen (desde un png)
Como indican los comentarios, la primera linea es saber donde esta la imagen base, la segunda es para importarla como PNG, tambien se puede hacer para jpg
imagecreatefromjpeg
o con gif
imagecreatefromgif
(aqui hay mas funciones parecidas: http://us3.php.net/manual- lookup.php?pattern=imageCreateFrom&lang=es)
$fcolor=ImageColorAllocate($img,255,120,0); // El color de las letras ($img,r,g,b)
Prepara el color de las letras en la imagen (recuerda que la imagen esta en $img), el color se asigna en rgb, de 0 a 255 (esta combinacion, "255,120,0", seria naranja)
$ip=$_SERVER['REMOTE_ADDR']; //La ip esta en la variable
Guarda la ip (que esta en la variable $_SERVER['REMOTE_ADDR'])
ImageString($img,5,65,75,"IP: $ip",$fcolor);
Escribe en la imagen, con tamaño de letra 5, desde el pixel 65 (horizontal) y el 75 (vertical), la cadena "IP: $ip",en el color $fcolor
El resto es hacer lo mismo con lo que nos interesa (lenguaje, navegador,etc...)
Y despues
Header("Content-Type: image/png"); // Avisamos que es una imagen png
Avisamos al navegador para que reconozca lo que viene ahora como una imagen png (si es jpg, habria que poner "image/png")
Y los dos ultimos pasos
ImagePNG($img); // Convertimos a png ImageDestroy($img); // Liberamos el espacio
Resultado:
Suerte y hasta otra
Gráficos de tortuga sobre imágenes en Python
Pues hoy traigo una mini-libraría que se apoya en PIL para hacer gráficos de tortuga directamente sobre imágenes [ imgturtle.py ]:
Dibujado con este script [ dragon.py ]
La idea es que se acerque lo máximo posible a la implementación oficial de los gráficos_de_tortuga_de_python con el añadido de poder guardar las imágenes ( y más velocidad me atrevería a decir ).
Al comenzar hay que crear un objeto imgturtle, que maneja la imágen, al inicializar el objeto se debe pasar un parámetro, una tupla de números que defina el tamaño en 'x' y en 'y' de la imágen o bien una cadena con el nombre del archivo del que se va a partir:
t = imgturtle( ( x, y ) ) # Nueva imágen
t = imgturtle( argv[ 1 ] ) # Imágen basada en otra
Una vez creado el objeto se puede disponer de los métodos habituales de estos gráficos:
imgturtle.clear( ): # Vuelve a la imágen original
imgturtle.reset( ): # Reinicia la tortuga
imgturtle.save( fname ): # Guarda la imágen
imgturtle.rt( angle ): # Gira a la derecha con un ángulo || imgturtle.right()
imgturtle.lt( angle ): # Gira a la izquierda con un ángulo || imgturtle.left ()
imgturtle.fd( steps ): # Avanza unos pasos || imgturtle.forward()
imgturtle.bk( steps ): # Retrocede unos pasos || imgturtle.backward( )
imgturtle.pu( ): # Levanta el lápiz
imgturtle.seth( angle ): # Establece el ángulo ||imgturtle.setheading()
imgturtle.goto( x, y ): # Se mueve hasta una posición
imgturtle.pencolor( color ): # Establece el color que se pinta
imgturtle.home( ): # Vuelve a la posición inicial
imgturtle.pd( ): # Baja el lápiz || imgturtle.pendown() imgturtle.down()
imgturtle.pu( ):# Levanta el lápiz || imgturtle.penup() imgturtle.up()
imgturtle.heading( ): # Devuelve el ángulo de la tortuga
imgturtle.pos( ):# Devuelve la posición de la tortuga || imgturtle.position()
Nota: el sistema de coordenadas no está centrado en ( 0, 0 ), sinó en x / 2, y / 2
imgturtle.isdown( ): # Si el lápiz está bajado
Y eso es todo, por último un ejemplo dibujando sobre una imágen ya existente [ rayar.py ]. Original:
Después de "$ ./rayar.py base.png out.png":
Hasta otra
Recuperar una "HOME" cifrada desde un live cd
Supongamos que hemos cifrado la carpeta de usuario (Trisquel y Ubuntu dan esa posibilidad al instalarlo), y por cosas de la vida perdemos la posibilidad de acceder al SO, pero seguimos teniendo acceso a la particion con los datos ( y la clave, se entiende ). Esto es lo que podríamos hacer desde un LiveCD para volver a montar la partición:
Nota: substituye $DRIVE por la ruta hacia la particion home + .ecryptfs, por ejemplo sería /media/blablabla/.ecryptfs/
[ 1 ] Obtener clave del sistema de cifrado, contenida en $DRIVE/<nombre de usuario>/.ecryptfs/wrapped-passphrase , y envuelta con la contraseña del usuario.
1 2 3 |
|
Entonces e25c829b60e65e63a1ec2b9581ae4d4a sería la clave con la que se cifraron los datos, pero queda otra, a partir de Ubuntu 9.04 se cifran por defecto tambié los nombres de archivo.
[ 2 ] Obtener la clave que cifra los nombres de los archivos.
1 2 3 4 |
|
La segunda, b906f5e58bfbce18, es la que cifra los nombres de los archivos.
[ 3 ] Montar el sistema de archivos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Ya está!
Y, aunque no sea necesario decirlo, para desmontar el sistema de archivos al final:
1 |
|
Hasta otra
Ojo con las @ en las url
Cuidado con ellas, que el navegador piensa que lo que va antes es el usuario [ y contraseña ] para acceder a la pagina, algo como http://google.es: blablabla@codigoparallevar.co.cc/blog.
Si entras en esa pagina acabaras en codigoparallevar.co.cc, y con un blablabla
algo extenso puede pasar por un link legítimo, curiosamente distintos
navegadores reaccionan de distinta forma:
* Firefox 6.0.2 release: muestra un popup con el texto 'Está a punto de
iniciar sesión en el sitio "codigoparallevar.co.cc" con el nombre de
usuario "google%2Ees", pero el sitio web no requiere autenticación. Es
posíble que esto sea un intento de engaño'.
* Midori 0.2.4, Chromium 12, links2 y Chrome(por piou) : no muestra
ningún aviso y en la url no muestra lo que hay antes del @.
* Lynx: Muestra un aviso 'Alert!: Address contains a username: google.es:
blablabla' mientras carga, después lo muestra ( en este caso no se
muestra la URL ).
* Opera (por helq): No muestra ningún mensaje.
*
* Elinks (por mungu): no muestra nada
*
Sabeis como reaccionan otros navegadores?
El hackmeeting de este año es en A Coruña
**** Hackmeeting@A_Corunha ****
**** 21, 22 y 23 de Octubre ****
**** ¿Qué es Hackmeeting? ****
=====================================================================
Hackmeeting es un encuentro libre y autogestionado que gira en torno
a las nuevas tecnologías, sus implicaciones sociales, la libre
circulación de saberes y técnicas, la privacidad, la creación
colectiva, el conflicto telemático... Está destinado a todo tipo de
personas que tengan una mente abierta y curiosa con ganas de
compartir sus experiencias y vivirlo participando en la coordinación
como una más. Algunas charlas y talleres exigen conocimientos
informáticos avanzados, otros no; y otros ni informáticos.
( Sacado_del_Wiki )
El hackmeeting de este año se celebra en A Coruña ( que a mano que me queda! ^^ ), ya hay propuesto_un_nodo_sobre_IPv6 y hay información varia en el Wiki.
Ahí nos vemos... a ver si saco tiempo para proponer un nodo sobre redes anónimas :)