Macro para recorrer y editar entradas de la tabla de contenidos en Writer

Supongamos que quieres recorrer la tabla de contenidos de un documento Writer para modificar automáticamente algunas de las entradas. Por ejemplo, supongamos que quieres cambiar las entradas que empiezan por » PARTE» (como » PARTE  1″, » PARTE 2″…) por el mismo contenido pero en negrita, y añadirle un salto de línea a continuación. Es decir, quieres modificar el índice de contenido de la imagen de la izquierda para que quede como el de la derecha.

Selection_468

Selection_469

 

 

 

 

Puedes usar la siguiente macro StarBasic en LibreOffice Writer (Herramientas / Macros / Organizar macros / LibreOffice Basic …) :

' Dentro del Módulo1 de "Mis macros", en concreto en el método Main
Dim SearchDesc, oVC, Found, Cursor
Dim Fuera as Boolean 
 
   oDoc = ThisComponent ' oDoc es el documento actual
   SearchDesc = oDoc.createSearchDescriptor ' vamos a realizar una búsqueda
 
   With SearchDesc 
      .SearchString  = "^ PARTE.*$"   ' con esta expresión regular
      .SearchRegularExpression = True 
   end With
 
   oVC = oDoc.getCurrentController.getViewCursor  ' crear cursor para recorrer matches
   Fuera = false
   Found = oDoc.findFirst(SearchDesc) ' situarse en el primer match
 
   Do Until Fuera 
          Found.gotoStartOfSentence(false)  ' ir al comienzo de la línea (sin select)
	  Found.gotoEndOfSentence(true) ' seleccionar hasta final de línea
 
      Cursor = oVC.getText.createTextCursorByRange(Found) ' vamos a modificar la selec.
 
      if NOT IsNull(Cursor.DocumentIndex)  Then
        if NOT IsEmpty(Cursor.DocumentIndex)  Then
           Found.CharWeight = com.sun.star.awt.FontWeight.BOLD  ' por negrita
      	   Cursor.setString(CHR$(13) + Found.getString() + CHR$(13)) ' y salto de línea
           Found = oDoc.findNext(Found.End, SearchDesc) ' vamos a por siguiente match
        else
            Fuera = True
        end if
      end if   
   Loop

Instalar Ubuntu 13.04 en iMac 27″

Un apunte rápido, porque ha sido coser y cantar, a diferencia del martirio por el que tuvimos que pasar en 2010 y que dejamos documentado. Captura de pantalla 2013-09-06 a la(s) 16.13.39Realmente lo único que he necesitado ha sido la versión AMD64 de Ubuntu 13.04 (la vez anterior tuve que descargar explícitamente la versión «alternate», esta vez ha bastado con la versión desktop tradicional).

Sí ha sido necesario, al igual que la vez anterior, instalar el gestor de arranque rEFIt (no vale sólo con GRUB, o yo no he sido capaz). Parece que rEFIt está obsoleto y que ahora se recomienda rEFInd, aunque a mí no me ha dado ninguna guerra (al instalarlo, la primera vez no te saldrá el menú de rEFIt, tendrás que volver a arrancar para verlo).

El reparticionado del disco lo hice con el editor de disco de MacOSX. Sin problemas (reparticionando en caliente, sin desmontar la unidad… daba un poco de miedo, pero al no recibir ningún warning por intentarlo, supuse que era viable).

En la instalación, en modo gráfico, he seleccionado la opción de descarga de actualizaciones y la opción de activar drivers privativos. Nada más, Ubuntu 13.04 se ha instalado rápidamente en la partición que le corresponde y rEFIt me permite entrar sin problemas en MacOSX o Ubuntu (a través de GRUB).

Hay un fallo que queda por corregir: al apagar Ubuntu el iMac se queda colgado (no se llega a apagar). Para corregirlo:

sudo gedit /etc/default/grub

y sustituimos la línea GRUB_CMDLINE_LINUX_DEFAULT=”quiet splash” por GRUB_CMDLINE_LINUX_DEFAULT=”quiet splash reboot=pci”

(tal y como explicamos en el anterior post relacionado)

Nota: que a mí me haya funcionado no quiere decir que en tu iMac también lo haga. Así que, ya sabes, antes de tocar particiones, recuerda que las copias de seguridad son tus amigas 😉

Control de líneas huérfanas y viudas en LibreOffice Writer

Selection_427La Wikipedia define perfectamente las líneas viudas y huérfanas: son líneas que, por quedar en una página distinta que el resto del párrafo al que pertenecen, aparecen aisladas de su contexto.

En la imagen de la izquierda tenemos un ejemplo de línea viuda (aquella que, siendo la última de un párrafo, aparece al principio de la página siguiente). Una línea huérfana, por el contrario, sería aquella que aparece al final de una página, de forma aislada al resto de las líneas de ese párrafo (que continúa en la siguiente página).

Las líneas huérfanas y viudas quedan fatal en tus textos, ¿a que sí? Para controlarlas, LibreOffice Writer ofrece una sección «Flujo del Texto» en las propiedades del párrafo. Recomiendo que estas propiedades no se cambien párrafo a párrafo, sino que se apliquen al estilo por defecto. Pulsa F11 para ver los estilos que tienes aplicados en los párrafos. Si no has tocado nada, tendrás el «Estilo Predeterminado». Pulsa el botón derecho sobre ese estilo. Elige «Modificar» y sitúate en la pestaña «Flujo del Texto». En la parte inferior verás opciones para el control de huérfanas y viudas.  Por ejemplo, para «arreglar» automáticamente el problema de la figura anterior, le pediremos a LibreOffice que nunca deje viudas con menos de 3 líneas (ver imagen inferior). Lo que hará será reformatear automáticamente el texto para cumplir con nuestras órdenes. Lo mismo es aplicable para líneas huérfanas.

Selection_430Si a pesar de aplicar estas opciones algún párrafo en concreto se te resiste, siempre puedes forzar a LibreOffice a que no rompa ese párrafo entre páginas («No dividir párrafo») o a que un párrafo en concreto esté siempre junto al siguiente en la misma página («Mantener párrafos juntos»). Bueno, con estos trucos ya no hay excusa para que en tus documentos tengas líneas aisladas al comienzo o al final de página 😉

Referencias y bookmarks en LibreOffice

Selection_425 Redactando un documento te das cuenta de que quieres crear un enlace a sección del texto. Por ejemplo, estás redactando una receta y quieres crear un enlace a la zona de ingredientes. Lo mismo que cuando redactando un documento HTML quieres crear un enlace interno, de una parte del documento a otra. ¿Cómo hacerlo en LibreOffice Writer?

Lo primero que hay que hacer es determinar que la sección de ingredientes es un destino de salto. Seleccionamos una parte del texto de los ingredientes, por ejemplo, la cabecera. A continuación, en el menú Insertar, seleccionamos Referencia Cruzada. En la pestaña Referencias cruzadas, seleccionaremos «Establecer referencia» y le damos un nombre. Pulsamos el botón «Insertar» y «Cerrar».

En otra zona del documento, seleccionamos el punto en el que queremos crear el enlace a la referencia que acabamos de crear (el enlace que al pulsarlo, irá a la zona de ingredientes). Elegimos ahora «Insertar / Referencia cruzada» y en la pestaña «Referencias cruzadas», seleccionamos «Insertar referencia» y el destino del salto (en nuestro caso, sólo aparecerá listada la referencia «ingredientes» que hemos creado en el paso anterior). Pulsamos en «Insertar referencia a: Referencia», botón «Insertar» y «Cerrar». ¡Listo! Puedes probar que el enlace funciona correctamente situándote sobre él y pulsando el enlace (sin necesidad de pulsar simultáneamente Ctrl, como ocurre por ejemplo en la tabla de contenidos). Si todo ha ido bien, saltarás a la zona de ingredientes automáticamente.

¿Qué diferencia hay entre las referencias y los bookmarks (marcas de texto o marcadores) de LibreOffice? Si conviertes el documento con la referencia y salto a referencia cruzada que acabamos de crear a formato PDF o HTML, verás que el enlace se pierde. Si quieres mantener estos enlaces al exportar el documento a formato PDF o HTML, deberás  crear un bookmark en lugar de una referencia. Los bookmarks se crean mediante el menú «Insertar / Marca de texto…» . El enlace a un bookmark se crea de forma idéntica al enlace a una referencia (pero eligiendo «Marcas de texto» como destino, claro 🙂

Las cabeceras de nivel 1, 2, 3 y 4 generan referencias de forma automática, al igual que los pies de imagen (caption) y tablas, así que eso que te ahorras.  Recuerda este post cuando quieras crear referencias cruzadas a títulos de capítulo o subcapítulo. Recuerda también que las referencias se actualizan automáticamente al abrir un documento Writer. Si quieres forzar la actualización de referencias, pulsa F9.

#findelacita 😉

HackIt! 2013. Level 8. RPN (y II)

Warning: si no has intentando entender el intérprete RPN antes, ni te molestes en leer este post, porque te sonará a chino. Lo dejo explicado aquí para aquellos que se hayan pegado con este reto y no hayan obtenido la solución o estén totalmente atascados. Al resto de los mortales les puede explotar la cabeza (brainfuck!) si intentan comprender una mínima parte de todo lo que diga a continuación 🙂 Avisados quedáis.

Vamos a por ello, por partes. Para entender la primera sección del programa, le pondremos puntos de ruptura (bp=break point) allá donde creamos conveniente y ejecutaremos con:

./RPN -fprograma.txt

Ahora veremos que si ejecutamos ésto:

"aaaaaaaaaaaaaaaaa" 0Oo.oO0_ _ir]2;l[l6UmIvz3]S
bp 0ask ¿? -1neg [ 1 + @@ @ .] @@ 
}:-( 17k + [ @@ @ ¿? + 2 / .¿? 1 - @@ @ .]
¿? _d 0.6990432739 + - =>> 1zero 0one =>o) 

El programa se para al llegar a la instrucción bp, mostrándonos el contenido de la pila.

$ ./RPN -fretocado.txt 
Bpoint alcanzado
stack:97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 97.0000000000 0.0000000000 105.0000000000 114.0000000000 93.0000000000 50.0000000000 59.0000000000 108.0000000000 91.0000000000 108.0000000000 54.0000000000 85.0000000000 109.0000000000 73.0000000000 118.0000000000 122.0000000000 51.0000000000 93.0000000000 83.0000000000 | 
37: 0ask |

Los 97 del principio son el código ASCII de la letra «a». Suelo repetir esa letra en este tipo de pruebas en el que quiero ver cómo «evoluciona» el código con la entrada que le paso. Luego viene un 0, que corresponde al comando: 0Oo.oO0_ del churro de código que nos pasan. Es decir, parece que el intérprete, cuando ve una ristra de números y letras, sin espacios, interpreta los primeros dígitos como un número, hasta encontrarse con el primer carácter no numérico. En este caso, 0Oo.oO0_ = 0.
El 105, 114, 93…83 es el código ASCII del literal: _ir]2;l[l6UmIvz3]S (sin contar el _ que marca comienzo de literal).

El 0ask, se convertirá en un 0 en la pila. Lo podremos ver pulsando INTRO (ejecutar paso a paso). La siguiente instrucción, ¿?, parece que hace un simple pop (aunque luego veremos que no, que lo que hace es traer de memoria lo último que hayamos memorizado con el comando .¿? . Parece que si no hubiéramos memorizado nada es cuando hace un simple pop…luego lo veremos mejor). -1neg, empila un -1. Y llegamos a la definición de bucle, que comienza por [ y termina con ]
Las instrucciones del bucle se ejecutarán en cada ciclo, hasta que se cumpla la condición de salida. ¿Cuál es dicha condición? Si al llegar al cierre del bucle «]», la cima de la pila tiene un 0, saldremos, si no, seguiremos ciclando.

Así que empezamos con un -1 en la pila y nos metemos en el bucle: [ 1 + @@ @ .]
Lo que hace es empilar el 1, y luego sumar (-1 + 1 = 0). A continuación, @@ duplica la cima (tendremos 0 0) Luego llega una instrucción que nos trajo de cabeza hasta que conseguimos entenderla: @. Esta instrucción hace algo como lo siguiente:

offset = pop();
push(pila[offset])

Así que en la primera vuelta, hacemos un push(pila[0]). Como en la posición 0 de la pila tenemos nuestra primera letra del posible pass, estamos haciendo push(97).

Como 97 != 0, seguimos ciclando (.] cicla haciendo antes pop). En la siguiente vuelta tenemos 0 + 1 = 1. Duplicamos el 1 con @@ (1 1) y la sentencia @ empila el segundo carácter del pass (push(pila[1])). Seguiremos haciendo ésto hasta recorrer todos los caracteres del posible password. El siguiente carácter es un 0 (el que venía de 0Oo.oO0_). Es decir, al abandonar el bucle tendremos en la cima de la pila la longitud del posible pass (tras las pruebas supimos que era 17 la longitud de dicho pass). Lo duplicamos con @@ (17 17) y luego llega el comando }:-( que desempila y guarda en memoria ese valor (17) . A continuación 17k = empilar un 17 (17 17). «+» sumar los dos valores de la cima de la pila. nos quedamos con 34. Luego, el autor del level nos volvió locos con esto: [ @@ @ ¿? + 2 / .¿? 1 – @@ @ .]
Realmente lo que está haciendo (con ese @) es capturar la posición 34 (que quedaba tras la suma de 17 y 17) y traerlo a la pila. ¿Qué hay en esa posición? Es el último carácter del literal que empilamos al principio: _ir]2;l[l6UmIvz3]S , es decir, la S (ASCII:83). Lo suma con lo que hubiera en memoria (el famoso comando ¿? Inicialmente parece que tenemos un 0 -> 83 + 0 = 83. A continuación lo divide entre 2 y lo memoriza con el comando .¿?, sacándolo de la pila (tenemos en memoria un 41.5. En la cima de la pila un 34). Restamos 1 (tenemos 33) y volvemos a repetir el proceso: push(pila[offset]) (con offset = 33 obtenemos el carácter «]» (ASCII:93) (del literal _ir]2;l[l6UmIvz3]S). Le sumamos el contenido de la memoria (el 41.5), dividimos entre 2 y guardamos el resultado, memorizándolo (67.25) y sacándolo de la pila. Seguimos así hasta la condición de salida (hasta alcanzar el 0 de 0Oo.oO0_ .

¿Qué tiene que dar? Pues si la longitud del posible pass es 17, al haberlo duplicado tenemos un 34 (lo que nos permite recorrer el literal _ir]2;l[l6UmIvz3]S hacia atrás, operando como he explicado y dando como resultado el valor 100.6990432739. Lo tendremos en memoria y lo recuperaremos con «¿?». Luego el código empila «_d» (un 100 en ASCII), al que le suma «0.6990432739» (tenemos 100.6990432739) y resta ambos valores. Lo dicho, si la longitud del pass era 17, ahora estaremos restando 100.6990432739 – 100.6990432739 lo que dará 0. Si así fuera, saltaremos a la etiqueta «>». Esto fue otro quebradero de cabeza. Las sentencias «=>XXXX» son JUMPS condicionales. Si el valor de la cima de la pila es 0, salta a XXXX. Si no, sigue el flujo en la siguiente instrucción. En nuestro caso es 0, por lo que saltaremos (salto =>> a la etiqueta :> ) Una etiqueta comienza con «:», de ahí que saltemos a :>. De aquí, :> , empilamos 17, restamos a la cima – (nos quedamos con 0) y saltamos a «=>>>» (es decir, a :>>)

Aquí no me extenderé más, pero éste trozo de código:

:>>
0 .;) [ ;) @ sin 10 ;) 7con + ** @@ 1ocho % - @@ +>gen neg :gen 79O % 48$ + ;) }:-( 1Oo. ++ @ -

Realmente es el quid de la cuestión. Analiza cada carácter del posible pass y le aplica esta fórmula:

abs[sin(x) * 10 * (offset + 7)] % 79 + 48

Donde X es la letra del pass que estamos analizando cada vez (offset es la distancia hasta esa letra. offset 0 para la primera, offset 1 para la segunda, etc.). Cada letra X del pass, tras pasar por esa fórmula, tiene que dar los valores:

105, 114, 93, 50…. 83, es decir, los valores ASCII del famoso literal del principio
(ir]2;l[l6UmIvz3]S)

Basta con resolver esa ecuación para cada X y fin de la prueba… bueno, casí, porque por ejemplo, para la primera letra del pass, abs[sin(x) ….] = 105 no tiene una única solución. De hecho, hay 3 posibles soluciones. Lo mismo ocurre para otras cuantas letras (fijaros en la foto que publiqué de la primera parte de la solución de este nivel). Lo que nos dejó probando varias soluciones hasta alcanzar la buena. Cuando la lees te das cuenta de que tiene sentido al leerla en hAx0r, pero … no fuimos los únicos, @navarparty también se divirtió probando un rato 🙂

Aunque parezca mentira, nos gustó este puzle mental 🙂 pero metimos horas por un tubo para resolverlo. Algún año estaría bien que los autores de los retos del año anterior nos contaran cómo demonios se les ocurrió, así como el proceso de creación que llevaron a cabo hasta obtener este tipo de levels de artesanía pura.