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
Escribiendo un parser de Brainf*ck con BLK
¡Por fin! a estas alturas BLK permite compilar un razonable subset de C... bien, vale, faltan punteros y estructuras para tener algo decente, pero los primeros son escabrosos de simular con el intérprete, y las estructuras están en camino. Lo importante es que la estructura general es medianamente estable, aún dentro de la rama de prototipado, una consecuencia es que está abierto a cualquier participación :), así que veamos un ejemplo de como escribir un pequeño parser para brainf*ck.
Lo primero que haremos será importar el gestor de bytecode y preparar una constante para manejar el tamaño de la memoria, que en este caso será estática
from bytecode_manager import *
MEM_SIZE = 1024
El parser lo encapsularemos en una clase, con esta forma
class BrainfuckParser:
code = "" # Unparsed code
_bytecode_manager = None # Bytecode manager
global_frame = None # The global function
Ahora viene la función para inicializar la clase, recibe el gestor de bytecode como único parámetro
def init(self, bytecode_manager):
self._bytecode_manager = bytecode_manager
Ahora tenemos que preparar un espacio para el código, el código se agrupa en frames (que vienen siendo como bloques en C, pueden representar funciones, bucles o condicionales), al menos uno es necesario para que el código sea ejecutable por el intérprete, llamemosle '_start'
self.global_frame = gframe = bytecode_manager.add_function("_start", void_type, [])
La sintaxis es:
Bytecode_manager.add_function(
Ahí dentro ya podemos definir variables y operaciones, creemos manualmente una variable cursor para controlar la posición en memoria, y asignémosle el valor 0
bytecode_manager.add_variable("cursor", int_type, gframe, "Cursor variable")
bytecode_manager.add_op(ASSIGNATION_OP, {"name": "cursor"}, 0, gframe)
Ahí tenemos dos funciones, la primera es Bytecode_manager.add_variable, recibe como parámetros el nombre de la variable, su tipo, el frame y opcionalmente un comentario sobre el uso de la variable. Bytecode_manager.add_op añade una operación al frame, el primer parámetro es el tipo de operación, el segundo una referencia a la variable donde se guardará el resultado, la tercera los parámetros (sería una lista si hay más de uno), y la cuarta el frame.
También podemos crear un nuevo tipo para representar nuestras variables, por ejemplo un array para la memoria, los tipos se representan como diccionarios con al menos el valor 'byte_size' que indica que cantidad de bytes se le dedicarán, además hay otros atributos que se pueden usar, como 'structure', que indica el tamaño de las dimensiones del tipo, por ejemplo [2, 3] para un array de 2x3
tmp = {"byte-size": 4, "structure": [MEM_SIZE]}
bytecode_manager.add_variable("mem", tmp, gframe, "Machine memory")
También se puede hacer lo mismo con las referencias a variables, si se indican con un diccionario se puede especificar en 'pos' que parte 'atacar'
def parse_brainfuck(self, frame):
pointed_ref = {"name":"mem", "pos": ["cursor"]}
cursor_ref = {"name":"cursor"}
El resto de la función parse no necesita de nada nuevo, solo operaciones ADD_OP y SUB_OP sobre las dos referencias que acabamos de definir, menos el '[' que mencinaremos a continuación
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 una operación de control de flujo utilizaremos Bytecode_manager.add_branch, pasandole como primer parámetro el tipo de ramificación (WHILE_BRANCH, IF_BRANCH, ELSE_BRANCH o DO_WHILE_BRANCH), el segundo parámetro es la condición, si es distinto de 0 se ejecuta el condicional o se sigue en el bucle, el tercero es el frame, además acepta otros dos más, uno para las operaciones que se realizarán antes de comprobar la condición, y el último para las operaciones que se realizaran antes de estas a partir del segundo paso (el paso del 'for'), esta operación devuelve un frame para añadir las operaciones que toman lugar dentro de el
b = self._bytecode_manager.add_branch(WHILE_BRANCH, pointed_ref, frame)
El resto del código es lo suficientemente genérico como para necesitar casi ninguna 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)
Lo que si que se hace necesario mencionar es Bytecode_manager.add_entry_point que indica la función por la que entrar y Bytecode_manager.save para guardar el código
El código completo está aquí:
brainfuck_parser.py Hasta otra
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 :)