Custom JavaFX components in SceneBuilder

So you want to open a JavaFXML with a custom component in SceneBuilder?

This week I have been playing with this project: https://github.com/Vuzi/twitter-c 

an implementation of a Twitter Client in JavaFX. 

The application uses different JavaFX views, being the main one TweetListView: https://github.com/Vuzi/twitter-c/blob/master/src/main/resources/fr/esgi/twitterc/view/TweetListView.fxml

When running, the TweetListView displays a lot of elements (look at those pretty buttons, they are using the FontAwesomeFX library)

I wanted to open the FXML in SceneBuilder and inspect it. But on first try, it failed with a ClassNotFoundException:

That view.component.Icon is a custom component:

https://github.com/Vuzi/twitter-c/blob/master/src/main/resources/fr/esgi/twitterc/view/component/icon.fxml

used by TweetListView.fxml here:

https://github.com/Vuzi/twitter-c/blob/master/src/main/resources/fr/esgi/twitterc/view/TweetListView.fxml#L20

So, going through GitHub I found that, in order to edit that FXML in SB first we need to import a JAR file with the component in the Jar Manager of SB

https://stackoverflow.com/questions/29444698/how-to-create-an-fxml-file-for-an-already-created-new-component-in-java-than-add

But wait, how do we create the JAR file? I’m using IntelliJ so my explanations will be based on this IDE.

First, I isolated the component into a single repository:

https://github.com/juananpe/IconComponentFX

Let’s create a JAR of the IconComponent. In IntelliJ:

  1. Open Module Settings ⌘ ⬇️
  2. Click Artifacts
  3. Click the + Add button, point to JAR
  4. Select: From modules with dependencies…

In the next Window, Just click OK 

To generate the JAR, click on Build / Build artifacts / Build

IntelliJ will generate the jar file and place it in the out/artifacts folder

Now, let’s import the JAR of the IconComponent in  SceneBuilder

Open the JAR/FXML Manager

Click on Add Library from FileSystem

Click on Import Components.

And finally, we will be able to open without errors the TweeListView FXML in SceneBuilder:

See these references for more info:

SolveIt / Level 3 / EE30

Y con este SolveIt3 llegamos al final de los hackits y solveits que conseguimos resolver… fuera de tiempo, la mayoría, pero hey! No se puede tener todo… 🙂

Como suele ser habitual, el título de la prueba nos da una pista sobre lo que nos encontraremos: Frankly, an Antique Troll (FAT)

Se trata de una imagen de un disco formateado con un sistema de archivos FAT.

# fdisk -l disk.img.gz
Disk disk.img.gz: 146.5 MiB, 153600000 bytes, 300000 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xb24b8602

Device       Boot Start    End Sectors   Size Id Type
disk.img.gz1       2048 299999  297952 145.5M  c W95 FAT32 (LBA)

Podemos montar la imagen (renombrar primero para añadirle la extensión .dmg si estás en macOS):

➜ hdiutil attach disk.img.gz.dmg
/dev/disk2          	FDisk_partition_scheme
/dev/disk2s1        	Windows_FAT_32                 	/Volumes/NO NAME

Es curioso, en macOS monta la imagen sin problema, pero Linux se queja de que la imagen tiene algún error:

# fsck.vfat disk.img.gz
fsck.fat 4.1 (2017-01-24)
Logical sector size is zero.

# mount -o loop -t vfat disk.img.gz /tmp/q/
mount: /tmp/q: wrong fs type, bad option, bad superblock on /dev/loop10, missing codepage or helper program, or other error.

En macOS la imagen se monta por defecto en /Volumes/NO NAME. Si pedimos un listado de ese directorio:

$ ls -al
total 218505
drwxrwxrwx@ 1 juanan  staff        512 Aug  7 21:53 .
drwxr-xr-x  4 root    wheel        128 Aug  7 21:53 ..
drwxrwxrwx  1 juanan  staff        512 Aug  7 21:53 .fseventsd
-rwxrwxrwx  1 juanan  staff  111873298 Jul 22 10:00 video.avi

El .fseventsd es un artefacto de macOS. Y el vídeo, bueno… no hacía falta ni abrirlo para saber de qué se trataba:

Podía ser este o el trololó… 🙂

Desmontamos la unidad con umount /Volumes/NO\ NAME. Y empezamos a analizar el contenido de las particiones de esa imagen.

fdisk  disk.img.gz.dmg
Disk: disk.img.gz.dmg	geometry: 595/8/63 [300000 sectors]
Signature: 0xAA55
         Starting       Ending
 #: id  cyl  hd sec -  cyl  hd sec [     start -       size]
------------------------------------------------------------------------
 1: 0C    0  32  33 -   18 171  57 [      2048 -     297952] Win95 FAT32L
 2: 00    0   0   0 -    0   0   0 [         0 -          0] unused
 3: 00    0   0   0 -    0   0   0 [         0 -          0] unused
 4: 00    0   0   0 -    0   0   0 [         0 -          0] unused

Eliminamos los primeros 2048 bloques y extraemos el resto:

dd if=disk.img.gz.dmg of=/tmp/cabecera3 bs=512 skip=2048 count=297952

Probamos algo típico en un binario (ya hicimos pruebas con binwalk y no salió nada)… abrirlo con Gimp en modo raw 🙂

Hay que jugar con el ancho hasta que veamos algo parecido a la imagen…

Si le damos un poco de zoom, veremos lo que estábamos buscando (saludos a Cuartango, que fue el primero en encontrar la medida exacta)

Un S3ct0rde4Tb…

SolveIt / Level2 / EE30

El level 2 del SolveIt se nos hacía conocido. Surgió en alguna otra ocasión, no recuerdo exactamente… tal vez en la Gipuzkoa Encounter de 2019. El autor (@imobilis) dibujó las pistas para solucionarlo en un papel que luego troceó y revolvió en múltiples pedazos. Verdaderamente es un buen rompecabezas.

Solve It 2: Rompecabezas. Inicialmente la imagen era de baja calidad. A lo largo del torneo el autor proporcionó nuevas imágenes donde podía observarse mejor cada una de las piezas.

Conocíamos el procedimiento de resolución: recortar cada una de las piezas e intentar recomponer la imagen original. Un trabajo de chinos. Kotxerra se puso a ello y estuvo dándole al Photoshop durante horas. Al final consiguió una buena imagen:

Completar el puzle nos llevó más horas de las que hubiéramos querido meter en este level, pero el esfuerzo mereció la pena.

@ochoto retocó la imagen para hacerla más legible:

Aunque se ve mejor, te reto a que busques ahora la solución…. Hint1: la primera palabra de la solución se lee bastante bien: «Repeated».

Hint2: Los solveits repetidos no son un pecado… 😉

SolveIt / Level1 / EE30

Los bolsillos de un ORG, así se titulaba el level 1 del SolveIt. Venía acompañado de la típica imagen con varios elementos cuyos nombres hay que encontrar para formar la contraseña. Pero otra vez, nos encontramos con un red herring, una falsa pista que nos hizo perder tiempo (jugando con Google Lens para encontrar algunos nombres…) Al final bastaba con seguir la siguiente pista al pie de la letra: buscamos los nombres de los técnicos (orgs) que podrían llevar cualquiera de estos elementos…

Los elementos de la imagen al final no eran necesarios para encontrar la solución

Así que buscando en la intranet, pudimos ver esta lista:

Agradecer a los técnicos de la Euskal su labor tampoco está de más 🙂

Y nuestro compañero Cuartango, después de haber probado otras cuantas posibles soluciones, llegó a la conclusión de que la más simple era la buena: Aitor Aritz Gorka Mikel Oier 🙂

HackIt’2022/EE30/Level3 – Asahi Linux

El nivel 3 nos consiguió engañar. Y eso que lo esperábamos… una prueba sobre Asahi Linux va a caer sí o sí; marcan ha estado metiendo miles de horas en este proyecto…

El nivel 3 es mucho más fácil de lo que parece…

Descomprimiendo el fichero zip que nos adjuntan en la prueba analizamos lo que tenemos:

Lo primero, el nombre del gz indica AGX, la arquitectura GPU del M1 (Apple Silicon). Tras leer los posts de Rosenzweig y curiosear el repositorio GitHub de Asahi, llegamos hasta este script que trata de mostrar en pantalla el conejo típico de testing:

Además, usa variables del cmdbuf.json que nos dan (depth_bias_array, scissor_array…) Así que nuestra idea era ejecutar el código de renderizado del conejo en un m1 y si funcionaba, cambiar los .bin por los que nos daban (y cargar adecuadamente las variables del cmdbuf.json). Había algunos flecos más que arreglar, pero bueno… lo primero era encontra un m1 🙂 Afortunadamente para nuestros bolsillos podemos alquilar el uso de un mac mini m1 por 2.5€ al día.

No será por no haberlo intentado con un M1 real

Seguimos el script de instalación de Asahi hasta el final:

Pero llegamos a un punto interesante… En el último paso Asahi nos pedia apagar el M1 y en el arranque seleccionar Asahi… No contamos con un «pequeño» detalle: en un ordenador remoto al arrancar no tenemos acceso a la pantalla de boot. Así que se nos quedó el m1 en modo rebooting durante toda la party. Dimos la orden de reinstalar el sistema pero no se podía porque estaba en modo rebooting ¯\_(ツ)_/¯

Así que estuvimos dando vueltas y vueltas… sin darnos cuenta de un detalle. Si hay que renderizar algo en pantalla a partir de vértices de un gráfico, necesitaremos esa malla de vértices en 3d… que estará en alguno de los .bin que nos pasan.

En este obj_150138c000.bin, por ejemplo. Si pintamos esos puntos con matplotlib (saludos a @ochoto, que se curró el script):

#!/usr/bin/env python
# coding: utf-8

import numpy as np
import matplotlib.pyplot as plt

with open("obj_150138c000.bin", 'rb') as f:
    data = np.fromfile(f,dtype="f")

numvertex = len(data) // 3
rshp = data.reshape(numvertex,3)

xs = rshp[:,0]
ys = rshp[:,1]
zs = rshp[:,2]

plt.plot(xs,ys)
plt.show()

Y obtenemos el resultado buscado 🙂

Una vez visto, parece fácil, ¿a que sí?