]> git.jsancho.org Git - blog.git/commitdiff
Merge branch 'master' into spanish spanish
authorJavier Sancho <jsf@jsancho.org>
Fri, 2 Jul 2021 11:38:14 +0000 (11:38 +0000)
committerJavier Sancho <jsf@jsancho.org>
Fri, 2 Jul 2021 11:38:14 +0000 (11:38 +0000)
haunt.scm
images/dashboard.jpeg [new file with mode: 0644]
images/form.jpg [new file with mode: 0644]
images/lugaru.jpg [new file with mode: 0644]
posts/101.html
posts/115.html
posts/154.html
posts/20171227-midgaard_bot.html [new file with mode: 0644]
posts/20180223-lugaru.html [new file with mode: 0644]
posts/20180713-business_interfaces.html [new file with mode: 0644]
posts/20180802-kivyforms.html [new file with mode: 0644]

index 89b8e7edd2ab4336fd4aa0abf934837c900da218..21cb4ce8d49334440610e820671ac108e5750e51 100644 (file)
--- a/haunt.scm
+++ b/haunt.scm
@@ -66,7 +66,8 @@
                                  (li (@ (id "blog-title-header"))
                                      (a (@ (href "index.html"))
                                         (h1 ,(assoc-ref metadata 'author)))))
-                             (ul (@ (class "navigation-items center")))
+                             (ul (@ (class "navigation-items center"))
+                                 (li (a (@ (href "https://en.jsancho.org/")) "in english")))
                              (ul (@ (class "navigation-items right"))
                                  ,@(map (lambda (page)
                                           `(li (a (@ (href ,(cdr page))) ,(car page))))
                                 ,(post-date-and-tags (post-date post) (get-tags post)))
                                ,(post-summary post)
                                (footer (@ (class "read-more"))
-                                          (a (@ (href ,(post-uri post))) "...read more..."))))
+                                          (a (@ (href ,(post-uri post))) "...seguir leyendo..."))))
                    (posts/reverse-chronological posts))))))
 
 (define about-page
   (static-page
-   "About me"
+   "Sobre mi"
    "about.html"
-   `((h2 "hi."))))
+   `((div
+      (article
+       (header (h2 "Sobre mi"))
+       (img (@ (src "images/jsancho.jpg") (width "150") (height "150") (align "left") (style "margin: 10px;")))
+       (p "Me llamo Javier Sancho y soy programador y defensor del software libre. Vivo en Castellón, España.")
+       (p "Conocí GNU/Linux y el software libre durante mis estudios universitarios en la " (a (@ (href "http://www.uji.es/")) "Universitat Jaume I") " y desde entonces mi compromiso con esas ideas ha ido en aumento.")
+       (p "Fue en 2003 cuando empecé como activista, participando en eventos relacionados con el software libre, manifestaciones en contra de las patentes de software, charlas y jornadas informativas en parties, institutos, etc.")
+       (p "Disfruto programando y lo hago con el lenguaje que más se ajuste a mis necesidades (Python, PHP, Golang, Erlang, ...). Durante muchos años mi lenguaje favorito fue C, aunque con el tiempo ese lugar privilegiado han pasado a ocuparlo Lisp y Scheme a partes iguales. Soy un enamorado del paradigma funcional.")
+       (p "Estoy casado con una mujer maravillosa y tengo un hijo que no deja de sorprenderme cada día. Son mi mayor alegría.")
+       (p "Aparte de este blog, a veces comparto pensamientos en " (a (@ (href "https://twitter.com/jsancho_gpl")) "Twitter") ". Puedes contactar conmigo en " (a (@ (href "mailto:jsf@jsancho.org")) "jsf@jsancho.org") "."))))))
 
 (define %collections
   `(("Home" "index.html" ,posts/reverse-chronological)))
 
 (site #:title "Javier Sancho"
       #:domain "jsancho.org"
+      #:build-directory "site"
       #:default-metadata
       '((author . "Javier Sancho")
-        (description . "Free Software Evangelist - Programmer")
+        (description . "Evangelizador del software libre - Programador")
         (email . "jsf@jsancho.org")
         (picture . "images/jsancho.jpg")
-        (pages . (("projects" . "http://git.jsancho.org/")
-                 ("about me" . "about.html"))))
+        (pages . (("proyectos" . "http://git.jsancho.org/")
+                 ("sobre mi" . "about.html"))))
       #:readers (list sxml-reader html-reader)
       #:builders (list (blog #:theme flex-theme #:collections %collections)
                        (atom-feed)
diff --git a/images/dashboard.jpeg b/images/dashboard.jpeg
new file mode 100644 (file)
index 0000000..fdcf8b2
Binary files /dev/null and b/images/dashboard.jpeg differ
diff --git a/images/form.jpg b/images/form.jpg
new file mode 100644 (file)
index 0000000..f77f6ec
Binary files /dev/null and b/images/form.jpg differ
diff --git a/images/lugaru.jpg b/images/lugaru.jpg
new file mode 100644 (file)
index 0000000..7e90e5f
Binary files /dev/null and b/images/lugaru.jpg differ
index 267536b5dcbf8def7c1861c2d4003fe195826b8d..0690ff98771d5e82f72578363366ab2b9b744b7f 100644 (file)
@@ -4,5 +4,5 @@ date: 2006-03-17 09:58
 <div>
 <p>No suelo hacer ningún test friki de esos que hay por ahí, pero para uno que hago el resultado me encanta :-D</p>
 
-<p><a href="http://www.emezeta.com/testometro/"><img src="http://www.emezeta.com/testometro/personalidad/indy.png" alt="indy"/></a></p>
+<p><a href="http://www.emezeta.com/testometro/"><img src="https://www.emezeta.com/testometro/personalidad/indy.png" alt="indy"/></a></p>
 </div>
index a1ff24ac8bff9098316044bd48909a2895469019..d7e7c26e34b38006e6162eda68c79b6d4b07b6bb 100644 (file)
@@ -2,7 +2,7 @@ title: Lotb, un sistema multiblog GPL
 date: 2007-03-30 16:49
 ---
 <div>
-<p><img width="89" height="100" border="0" align="left" alt="Lotb Logo" src="http://www.nongnu.org/lotb/img/logo.png" />Lord of the Blogs (Lotb) es un sistema multiblog en el que llevo trabajando unos meses. En si mismo no es un blog, pero permite centralizar la gestión de distintos blogs desde un único sitio. Su particularidad es que los blogs pueden encontrarse en distintos servidores, usar distintas bases de datos e incluso distinto software. Por ejemplo, con Lotb podríamos usar un blog con Wordpress y otro con Textpattern en un servidor distinto, usando siempre el mismo software de gestión.</p>
+<p><img width="89" height="100" border="0" align="left" alt="Lotb Logo" src="https://www.nongnu.org/lotb/img/logo.png" />Lord of the Blogs (Lotb) es un sistema multiblog en el que llevo trabajando unos meses. En si mismo no es un blog, pero permite centralizar la gestión de distintos blogs desde un único sitio. Su particularidad es que los blogs pueden encontrarse en distintos servidores, usar distintas bases de datos e incluso distinto software. Por ejemplo, con Lotb podríamos usar un blog con Wordpress y otro con Textpattern en un servidor distinto, usando siempre el mismo software de gestión.</p>
 
 <p>Una utilidad bastante evidente para Lotb es usarlo para implementar granjas de blogs, aunque también puede ser usado por una sola persona para mantener sus distintos blogs. Al permitir blogs desde distintos servidores el sistema es fácilmente escalable sin que ello repercuta en el rendimiento global.</p>
 
@@ -12,7 +12,7 @@ date: 2007-03-30 16:49
 
 <p>Lotb se comunica con todos los blogs que cuelgan de él usando un sistema de mensajes para intercambiar información sobre usuarios, posts, estadísticas e información en general. También son usados para transmitir ordenes básicas. Los mensajes se firman para verificar el remitente, de forma que no se aceptan mensajes provenientes de fuera del sistema formado por Lotb y sus blogs dependientes. Los mensajes no se cifran ya que en ningún momento se transmite información confidencial como podrían ser contraseñas; solamente se transmiten los datos que muestran los blogs como pueden ser nombres, textos o comentarios.</p>
 
-<p><img width="485" height="368" border="0" align="middle" alt="Lotb Scheme" src="http://www.nongnu.org/lotb/img/diagrama.png" /></p>
+<p><img width="485" height="368" border="0" align="middle" alt="Lotb Scheme" src="https://www.nongnu.org/lotb/img/diagrama.png" /></p>
 
 <p>Los mensajes se agrupan en dos tipos: síncronos y asíncronos.</p>
 
index 356213dca3846a7dc29d67a015906739290e6d46..6cd87d7969d08c46abf5326a869014da0d03d2df 100644 (file)
@@ -1,4 +1,4 @@
-title: La perversión empesarial no tiene límites
+title: La perversión empresarial no tiene límites
 date: 2016-01-03 21:56
 ---
 <div>
diff --git a/posts/20171227-midgaard_bot.html b/posts/20171227-midgaard_bot.html
new file mode 100644 (file)
index 0000000..8cab6c8
--- /dev/null
@@ -0,0 +1,26 @@
+title: Midgaard Bot, conectando a un MUD con Telegram
+date: 2017-12-27 11:51
+---
+<div>
+  <p>Un compañero de trabajo, Vlad Nicu, está desarrollando un bot de Telegram para ofrecer información sobre criptomonedas (precio, etc). Tras hablar con él me entró el gusanillo de escribir un bot para conectar con un MUD (Multi User Dungeon) usando Telegram. Cuando era joven estuve mucho tiempo enganchado a este tipo de juegos online y me pareció divertido desarrollar algo del estilo.</p>
+
+  <p>Puestos a probar cosas decidí usar Golang y así practicar un poco con este lenguaje y sus gorrutinas. Como lenguaje, pienso que tiene muchas cosas que se podrían mejorar. En cuanto a la concurrencia nada que objetar, por supuesto. Es el punto fuerte de Go y se nota. Sí que es cierto que da la impresión de que la gente abusa de los canales y de las gorrutinas. He visto muchos ejemplos cuando me documentaba de problemas que se podrían haber resuelto simplemente con llamadas a funciones, sin usar tanta parafernalia.</p>
+
+  <p>El <a href="https://git.jsancho.org/?p=midgaard_bot.git;a=summary">código fuente de midgaard_bot</a> está disponible bajo licencia GPLv3.</p>
+
+  <p>Cuando el bot arranca, lanza una gorrutina que se queda escuchando los mensajes que le llegan desde Telegram. Cuando llega un mensaje comprueba si tiene una sesión abierta para el chat desde el que llega el mensaje. Lo normal es que cuando se trate del primer mensaje del chat no tenga sesión.</p>
+
+  <p>En el caso de no tener sesión, el bot lanza una nueva gorrutina para conectar por telnet al MUD y servir de conector entre Telegram y el juego.</p>
+
+  <p>Para controlar en qué momento la conexión telnet ha acabado de mandar un mensaje completo, y por lo tanto poder mandarlo a Telegram para que lo reciba el jugador, tuve que implementar un buffer que recogiera los datos que iban llegando desde el MUD y usar un timeout de 500 milisegundos, tras el cual se entiende que el mensaje está completo y se puede mandar. No es ninguna maravilla pero para conexiones locales funciona bien.</p>
+
+  <p>Cuando ya tenemos el mensaje completo lo mandamos a una gorrutina específica que se encarga de recibir mensajes desde las sesiones abiertas y los reenvía a Telegram.</p>
+
+  <p>Durante el desarrollo me ocurrió una cosa graciosa que me tuvo en jaque un buen rato y que te hace pensar en cómo funcionan en realidad las gorrutinas. La gorrutina que controla la sesión escribía un mensaje en un canal y se quedaba colgada. El problema estaba que aún no había implementado la otra parte del programa que leía de ese canal y los canales de Go son bloqueantes.</p>
+
+  <p>Al pensar en los canales yo tenía una idea de ellos similar a los mensajes de Erlang, que tienes un proceso que manda mensajes de forma asíncrona y y la ejecución sigue de forma independiente. Pero en Golang no es así, los canales no son "tuberías", son puntos de unión entre gorrutinas. Si escribes un mensaje en un canal, te quedas bloqueado hasta que otra gorrutina lee ese canal y libera a la gorrutina que ha escrito ese mensaje.</p>
+
+  <p>Cosas curiosas que tiene la concurrencia usando estos mecanismos.</p>
+
+  <p>Midgaard Bot está sin acabar y no creo que continue con su desarrollo, ya que mi objetivo era ver si podía conectar con el MUD a través de Telegram y eso ya está conseguido. Pero si alguien quiere seguir, en el repositorio están todas las bases para hacerlo crecer.</p>
+</div>
diff --git a/posts/20180223-lugaru.html b/posts/20180223-lugaru.html
new file mode 100644 (file)
index 0000000..7e0da6a
--- /dev/null
@@ -0,0 +1,19 @@
+title: Lugaru: los amigos de Turner
+date: 2018-02-23 10:31
+tags: juegos, lugaru
+---
+<div>
+  <a href="images/lugaru.jpg"><img src="images/lugaru.jpg" alt="Lugaru" width="300" height="225" class="image-left" /></a>
+
+  <p><a href="https://en.wikipedia.org/wiki/Lugaru">Lugaru</a> es un juego de acción en 3D en el que conduces al protagonista, el conejo Turner, a través de una serie de aventuras contra otros conejos hostiles y lobos. Turner es un experto en artes marciales. El <a href="https://gitlab.com/osslugaru/lugaru.git">código de Lugaru y sus contenidos</a> son libres.</p>
+
+  <p>Escribo sobre este juego porque se ha convertido en uno de los favoritos de mi hijo. Y eso es así por las enormes falicidades que proporciona el juego para editar niveles, añadir nuevos personajes, crear histórias nuevas y, en general, hacer lo que queramos con él.</p>
+
+  <p>Pero la cosa fue a más y pronto Roberto empezó a pedirme más cosas. Y es que, en Lugaru, Turner se enfrenta en solitario a todos los peligros y mi hijo quería poder contar con una serie de amigos que le ayudarán a combatir a las fuerzas del mal. Al principio le fui dando largas pero la insistencia de un niño de 5 años es poderosa y finalmente me puse a estudiar el código del juego para ver hasta qué punto podía complacerle.</p>
+
+  <p>Lugaru utiliza SDL, lo cual me sorprendió, ya que esperaba algún motor más evolucionado, y su código no está demasiado depurado y tiene muchas partes que se podrían refactorizar, pero usa nombres muy descriptivos para variables y funciones que me permitieron comprender en poco tiempo la estructura interna del juego y cómo podía conseguir lo que quería.</p>
+
+  <p>Tras una semana, podeis comprobar lo que he conseguido, que la verdad esta bastante logrado para la poca experiencia que tengo en este tipo de desarrollos. En <a href="https://git.jsancho.org/?p=lugaru.git;a=shortlog;h=refs/heads/improvements">mi rama personal de mejoras de Lugaru</a> podeis ver cómo he resuelto el problema y también he creado el vídeo <a href="https://www.youtube.com/watch?v=hk79QqtMcZo">Lugaru: los amigos de Turner</a> para que podais ver el resultado.</p>
+
+  <p>Seguro que con juegos privativos podeis hacer estas cosas igual de fácil, ¿verdad?</p>
+</div>
diff --git a/posts/20180713-business_interfaces.html b/posts/20180713-business_interfaces.html
new file mode 100644 (file)
index 0000000..b65c55e
--- /dev/null
@@ -0,0 +1,27 @@
+title: Consolas empresariales: ¿pasado o futuro?
+date: 2018-07-13 11:57
+tags: erp, datos, interfaz, empresa
+---
+<div>
+  <a href="images/dashboard.jpeg"><img src="images/dashboard.jpeg" alt="dashboard" width="300" height="200" class="image-left" /></a>
+
+  <p>Actualmente todas las empresas usan para sus actividades diarias todo tipo de programas empresariales o de gestión, como por ejemplo ERPs, CRMs, contabilidad, inventario, gestión de tiendas virtuales, etc. Y mucho antes que las empresas "de oficina" ya empezaron las fábricas, con sistemas de control para máquinas, vagonetas, control de carriles y todo tipo de automatismos. Podemos decir que no existe ningún proceso en la vida de una empresa que no tenga un programa directamente asignado para controlarlo.</p>
+
+  <p>Y aún podemos ampliar mucho más este control de los programas si añadimos conceptos como <a href="https://es.wikipedia.org/wiki/Macrodatos">Big Data</a> y <a href="https://es.wikipedia.org/wiki/Aprendizaje_autom%C3%A1tico">Machine Learning</a>, convirtiendo muchos de los procesos de la empresa en puros procesos automáticos y otros en procesos relativamente sencillos de gestionar.</p>
+
+  <p>Todos estos sistemas son, en su esencia, ecuaciones matemáticas y fórmulas que calculan resultados en base a unas entradas y que se encargan de transformar datos, pasándolos de una estructura cruda a algo que tiene sentido para el negocio y que lo impulsa, además de proporcionar información útil para mejorarlo.</p>
+
+  <p>A pesar de todo lo complejo que pueda parecer, estos sistemas no son demasiado complicados ya que están basados en reglas matemáticas cuya lógica es fácil de entender. Pero existe una variable que no he comentado y que cambia totalmente las reglas del juego, y es que estos sistemas no son meras cajas negras que guardamos en un cuarto oscuro y dejamos que hagan su trabajo, sino que necesitan trabajar con un ente bastante impredecible: el usuario, el ser humano.</p>
+
+  <p>En un principio esta comunicación programa-humano se realizaba mediante las típicas consolas de verde sobre negro que nos permitían introducir comandos que los programas obedecían. Con el tiempo, esas consolas han evolucionado hacia aplicaciones totalmente visuales con botones, formularios y menús y se han vuelto tan complejas que hemos creado un nuevo tipo de programadores, los encargados de desarrollar el "front-end", los que hacen que los programas sean intuitivos y fáciles de usar.</p>
+
+  <p>Pero en esta transformación los usuarios han perdido mucho más de lo que parece, han perdido su poder.</p>
+
+  <p>Me sorprendí muchísimo cuando descubrí que muchos matemáticos y científicos trabajan directamente con <a href="https://es.wikipedia.org/wiki/Python">Python</a> y con <a href="https://jupyter.org/">Jupyter Notebook</a>, es decir, que trabajan con una consola de texto aunque con muchas más funcionalidades que las de hace cincuenta años, en las que pueden visualizar tablas, gráficos, texto enriquecido, etc. Es cierto que tienen un perfil relativamente cercano al de los programadores, pero aún así no deja de ser sorprendente que prefieran la "rudeza" de la consola a los programas más visuales.</p>
+
+  <p>Y entonces caí en la cuenta de que el programa que más valoran en cualquier oficina no es el último ERP de moda; todo lo contrario, lo más valorado es el blanco cuadriculado de la hoja de cálculo. Al igual que para los matemáticos, la posibilidad de crear, de usar el poder de la máquina hasta su límite, es lo más valorado por cualquier profesional. Puede que al principio las interfaces elegantes ayuden mucho, pero a partir de cierto punto el usuario quiere ir más allá, quiere romper la barrera que existe entre el programa y el humano y hacer cosas increíbles que de otra forma no podría hacer.</p>
+
+  <p>Muchos programas se desarrollan teniendo en cuenta que se accederá a través de una interfaz gráfica, su arquitectura se ve condicionada por el front-end, y creo que es un gran error. Los programas deberían desarrollarse para ser usados a través de una consola de texto. Las interfaces gráficas tienen una utilidad que no debemos olvidar, pero el desarrollo de un programa debe estar centrado en los datos, no en la interfaz de uso.</p>
+
+  <p>Muchos ven las consolas de texto como algo del pasado, pero imaginad un futuro cercano dentro de veinte años. ¿Cómo usaremos los programas con reconocimiento de voz? ¿Se parecerán a las actuales interfaces gráficas? ¿O estaremos hablando a "consolas de voz"?</p>
+</div>
diff --git a/posts/20180802-kivyforms.html b/posts/20180802-kivyforms.html
new file mode 100644 (file)
index 0000000..880bf61
--- /dev/null
@@ -0,0 +1,95 @@
+title: Diseñando formularios con Python y Kivy
+date: 2018-08-02 13:40
+tags: formulario, python, kivy, kivyforms
+---
+<div>
+  <a href="images/form.jpg"><img src="images/form.jpg" alt="form" width="300" height="200" class="image-right" /></a>
+
+  <p>Existen muchas librerías para crear interfaces gráficas con Python. Por poner algún ejemplo, he probado con <a href="https://wxpython.org/">wxPython</a>, <a href="https://riverbankcomputing.com/software/pyqt/">PyQt</a> y <a href="https://kivy.org/">Kivy</a>. Esta última es la que más me ha gustado por una serie de razones:</p>
+
+  <ul>
+    <li>Es multiplataforma y funciona en GNU/Linux, Windows, OS X, Android, iOS y Raspberry Pi. Solo he probado las dos primeras pero sí que he podido comprobar que está pensada para usar con teclado y ratón o con pantallas táctiles.</li>
+    <li>No se basa en los widgets nativos de las plataformas sino que tiene los suyos propios, por lo que las aplicaciones se ven igual en todas las plataformas.</li>
+    <li>Es rápida; el motor gráfico funciona sobre OpenGL ES 2 y muchas partes están escritas en Cython.</li>
+    <li>Puedes diseñar las interfaces directamente desde Python o usando el lenguaje Kv.</li>
+    <li>Es un proyecto relativamente nuevo y con un buen mantenimiento.</li>
+    <li>Buena documentación y con muchos ejemplos.</li>
+  </ul>
+
+  <p>Estoy trabajando en un framework de desarrollo de aplicaciones, por lo que necesito que los desarrolladores puedan diseñar formularios rápidamente, al estilo WYSIWYG, y que además puedan incluir sus propios temas, colores, etc. El hecho de que exista el <a href="https://kivy.org/docs/guide/lang.html">lenguaje Kv</a> me facilita mucho la tarea. Es algo parecido al QML que tiene Qt y que permite guardar tus composiciones en ficheros de texto que pueden ser cargados despues por la aplicación sin tener que tocar nada de código.</p>
+
+  <p>Por ejemplo, el <i>Hello World</i> de <a href="https://kivy.org/">Kivy</a> se podría escribir así:</p>
+
+  <pre>
+    # main.py file
+    from kivy.app import App
+
+    class TestApp(App):
+        pass
+
+    TestApp().run()
+
+    # test.kv file
+    Button:
+        text: 'Hello World'
+  </pre>
+
+  <p>Para diseñar los formularios he creado un widget que proporciona un canvas en el que es posible añadir botones, etiquetas, campos de texto y cosas por el estilo. El proyecto se llama <a href="https://gitlab.com/jsancho/kivyforms">KivyForms</a> y de momento es beta. También podeis ver un <a href="https://www.youtube.com/watch?v=512Jfl2CUdY">vídeo con ejemplo de uso de KivyForms</a>. La idea es que el widget tenga una API potente para poder ser integrado en cualquier aplicación que necesite composición de formularios.</p>
+
+  <p>Mirad lo que contiene el widget:</p>
+
+  <pre>
+    class FormCanvas(BoxLayout):
+        def __init__(self, *args, **kwargs):
+            super(FormCanvas, self).__init__(*args, **kwargs)
+
+            self._canvas = StackLayout(
+                orientation='lr-tb',
+                padding=[10, 10, 10, 10],
+                spacing=[10, 10]
+            )
+            super(FormCanvas, self).add_widget(self._canvas)
+  </pre>
+
+  <p>El FormCanvas se basa en un BoxLayout de Kivy e internamente tiene un StackLayout que es donde realmente se añadirán los widgets del formulario. El StackLayout permite que los demás widgets se vayan apilando sin ocupar todo el tamaño de la pantalla.</p>
+
+  <pre>
+    def add_widget(self, widget):
+        g = Grabbable(
+            height=self.widgets_height,
+            size_hint=self.widgets_size_hint
+        )
+        g.add_widget(widget)
+        self._canvas.add_widget(g)
+  </pre>
+
+  <p>Cada vez que añadimos un widget se instancia un elemento <b>Grabbable</b> que contendrá al widget que queremos añadir. Es este elemento <b>Grabbable</b> el que realmente añadimos al canvas. Esto nos permitirá seleccionar el widget y moverlo por el formulario para diseñar la composición.</p>
+
+  <p>Existe un elemento <b>Destination</b> que sirve para indicar dónde caera el widget al finalizar la operación de arrastrar.</p>
+  
+  <pre>
+    class Destination(Label):
+        def __init__(self, **kwargs):
+            super(Destination, self).__init__(**kwargs)
+            self.text = 'Widget goes here'
+            self.color = [1, 1, 0, 1]
+            with self.canvas.after:
+                Color(1, 1, 0, 1)
+                self.box = Line(dash_length=8, dash_offset=4)
+
+        def update_box(self):
+            self.box.points = [
+                self.x, self.y,
+                self.x, self.y + self.height,
+                self.x + self.width, self.y + self.height,
+                self.x + self.width, self.y,
+                self.x, self.y
+            ]
+  </pre>
+
+  <p>Este elemento, que es una simple etiqueta con el borde punteado, es muy útil para que el desarrollador pueda ubicar los widgets en el lugar adecuado.</p>
+
+  <p>Por último, es posible exportar la composición a lenguaje Kv. KivyForms se encarga de eliminar los elementos <b>Grabbable</b> y todo el resto de la configuración necesaria para el diseño del formulario, de forma que es posible guardar la composición directamente a un fichero, lista para ser usada en nuestros programas.</p>
+
+  <p><a href="https://gitlab.com/jsancho/kivyforms">KivyForms</a> se distribuye bajo <a href="https://opensource.org/licenses/MIT">licencia MIT</a>. Aunque prefiero las licencias GPL, en este caso he decidido usar, por coherencia, la misma licencia que Kivy, así que estais invitados a colaborar en el proyecto.</p>
+</div>