<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>danigm.net - software</title><link>https://danigm.net/</link><description></description><lastBuildDate>Thu, 30 May 2024 00:00:00 +0200</lastBuildDate><item><title>rpmlint: Google Summer of Code 2024</title><link>https://danigm.net/gsoc-2024.html</link><description>&lt;p&gt;I'm glad to say that I'll participate again in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;, as
mentor. This year we will continue the work done during the past year,
as part of the &lt;a href="https://www.opensuse.org/"&gt;openSUSE&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;So this summer I'll be mentoring an intern and we'll continue working
on improving the testing framework of the &lt;a href="https://github.com/openSUSE/mentoring/issues/204"&gt;rpmlint project&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gsoc.png" /&gt;
&lt;/p&gt;

&lt;p&gt;This year we've a better testing framework, thanks to the work done
during the past Summer of Code, by Afrid. So the goal for this year is
to try to modernize existing tests and remove as much files as
possible from &lt;code&gt;test/binary&lt;/code&gt; directory, replacing those with mock
packages defined with python code.&lt;/p&gt;
&lt;p&gt;The selected intern is &lt;a href="https://blog-gsoc-2024.blogspot.com/2024/05/gsoc-improve-test-coverage-in-rpmlint.html"&gt;Luz Marina Montilla Marín&lt;/a&gt;. She has done
some initial work in the rpmlint project, creating the mock packages
for some tests and we've just started with the work to do during the
GSoC program, evaluating the tests that we've right now and planning
were to start.&lt;/p&gt;
&lt;p&gt;She studies at Córdoba, Spain, my hometown. Every year I try to reach
young people at different local universities, here in Andalucía, and
sometimes I'm able to convince some students to participate, like the
&lt;a href="https://danigm.net/gsoc-2020.html"&gt;GSoC 2020&lt;/a&gt;, when Alejandro Dominguez, from Seville, were working
on Fractal. So I'm happy that I'm increasing the number of free
software developers in my local community :D&lt;/p&gt;
&lt;p&gt;I'm sure that she will be able to achieve great things during these
three months, so I'm looking forward to start to code and see how far
can we go.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Thu, 30 May 2024 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2024-05-30:/gsoc-2024.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><item><title>rpmlint updates (August 2023)</title><link>https://danigm.net/rpmlint-updates-2023-08-30.html</link><description>&lt;p&gt;We are at the end of the summer and this means that this year Google Summer of
code is ending.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/rpmlint-gitg-gsoc-2023.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The recent changes applied now in the main branch include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove usage of &lt;code&gt;pkg_resource&lt;/code&gt; because it's deprecated.&lt;/li&gt;
&lt;li&gt;Fix elf binary check with ELF files with a prefix.&lt;/li&gt;
&lt;li&gt;New check for python packages with multiple .pyc files for different python
   versions.&lt;/li&gt;
&lt;li&gt;Improve the testing framework (merged the work done during the GSoC 2023)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Summer of Code 2023 updates&lt;/h2&gt;
&lt;p&gt;The summer of code is ending and the work done by &lt;a href="https://github.com/rpm-software-management/rpmlint/pull/1101"&gt;Afrid was good enough to be merged&lt;/a&gt;,
so I merged it the past week.&lt;/p&gt;
&lt;p&gt;I'm really happy with the work done during the GSoC program, now we've a more
simple way to define tests for rpmlint checks mocking the rpm, so it's not
always needed to build a fake rpm binary for each new test. This will make a
lot easier to create simple tests, so I hope that we can increase the code
coverage using this &lt;a href="https://github.com/rpm-software-management/rpmlint/blob/main/test/README.md"&gt;new framework&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During this time Afrid has extended the &lt;code&gt;FakePkg&lt;/code&gt; class, so it's possible now
to define fake metadata and files with fake tags and attributes. It's not
complete and it's not a simple task to replace all the &lt;code&gt;rpm&lt;/code&gt; binaries used for
tests, because the &lt;code&gt;Pkg&lt;/code&gt; class and &lt;code&gt;RPM&lt;/code&gt; tags is a complex thing, but the
current state allow us to replace a lot of them. Afrid has replaced some of the
tests that uses binaries, but in the following months we can continue working
on this and &lt;a href="https://github.com/rpm-software-management/rpmlint/issues/1105"&gt;replace more&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After this work, we can now start to use more the &lt;code&gt;FakePkg&lt;/code&gt; class in tests,
so another task that we can do is to provide some &lt;a href="https://github.com/rpm-software-management/rpmlint/issues/1104"&gt;common fake pkgs&lt;/a&gt; to use
in different tests and new checks, so now it's possible to create fake packages
with dynamic random data, so we can extend tests with fuzz testing and maybe
this will help to improve the tool reliability.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gsoc.png" /&gt;
&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I've participated as mentor several times now in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;summer of code&lt;/a&gt;, and
&lt;a href="https://www.outreachy.org/"&gt;outreachy&lt;/a&gt;, and almost always was a good experience. With the &lt;a href="https://www.gnome.org/"&gt;gnome foundation&lt;/a&gt;
in previous programs and this year with &lt;a href="https://www.opensuse.org/"&gt;opensuse&lt;/a&gt;. These two communities
are very open to collaboration and makes the whole process really simple, for
me as mentor, and also for the intern.&lt;/p&gt;
&lt;p&gt;I want to congratulate Afrid, because it was nice to work with him during this
summer, he has done a great work, not just technically, but communicating,
asking and finding his own solutions without requiring a continuous guidance.&lt;/p&gt;
&lt;p&gt;He is very passionate and looks like a nice person, so I hope that he will
continue around the open source, it could be opensuse, rpmlint or any other
community, but this kind of people is what you want to find in any community.&lt;/p&gt;
&lt;p&gt;After many years collaborating with different free software communities, it's
amazing that there are so many great people in every project, of course you can
find toxic communities and people, but in my experience, that's usually just
noise, there are a lot of nice people out there, doing a great work, and I'm
happy that young people like Afrid can be part of the free software movement,
because this is what makes the free software great, the people that is
working on it.&lt;/p&gt;
&lt;p&gt;So Thanks a lot to Google for another summer of code, thanks to SUSE for
letting me, and encourage me, to mentor, and thanks to all the free software
developers that are out there.&lt;/p&gt;
&lt;p&gt;I encourage everyone to participate in this kind of programs, for interns, it's
a good opportunity to learn and to make some money working on free software,
for mentors it's an opportunity to get some help in your project and help
newcomers to be part of the community.&lt;/p&gt;
&lt;p&gt;Have a lot of fun!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Wed, 30 Aug 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-08-30:/rpmlint-updates-2023-08-30.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><item><title>Python in openSUSE Tumbleweed</title><link>https://danigm.net/python-tw.html</link><description>&lt;p&gt;&lt;a href="https://www.opensuse.org/#Tumbleweed"&gt;openSUSE Tumbleweed&lt;/a&gt; is a rolling release distribution, so it's
ideal for developers and users that like to have the bleeding edge
software.&lt;/p&gt;
&lt;p&gt;It's also really "stable" to be a rolling release, from time
to time you can find a broken package because of one package is
updated and another one is not compatible yet, but it's something that
doesn't happen too often thanks to &lt;a href="https://openqa.opensuse.org/group_overview/1"&gt;openqa tests&lt;/a&gt;, so you don't
need to worry about a breaking system.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/python-tw.png" /&gt;
&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://www.python.org/"&gt;Python interpreter&lt;/a&gt; and a lot of &lt;a href="https://pypi.org/"&gt;python modules&lt;/a&gt;
in every Linux distribution, but Tumbleweed does an interesting thing
for Python.&lt;/p&gt;
&lt;h2&gt;Default Python version (python3 -&amp;gt; python-3.11)&lt;/h2&gt;
&lt;p&gt;If you don't worry about the python version, you can just rely on
&lt;code&gt;python3&lt;/code&gt;. In Tumbleweed &lt;code&gt;python3&lt;/code&gt; is not a real package, but the
default python version provides &lt;code&gt;python3&lt;/code&gt;, so depending on when you
install &lt;code&gt;python3&lt;/code&gt; you will get a different package, if you install
it today (August 2023) you'll get &lt;code&gt;python311&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In your system you'll have the &lt;code&gt;/usr/bin/python3&lt;/code&gt; binary that points
to the default python, so you don't need to worry about the current
version, you'll have there the default Python version for the
operating system.&lt;/p&gt;
&lt;p&gt;In addition to the Python interpreter, you can find in the
distribution a lot of python modules, but again you can use the
default version, so, for example, if you want to install &lt;code&gt;poetry&lt;/code&gt;, you
just use &lt;code&gt;zypper install python3-poetry&lt;/code&gt; and that will install
the real package &lt;code&gt;python311-poetry&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Multiple python versions (3.8, 3.9, 3.10, 3.11)&lt;/h2&gt;
&lt;p&gt;Besides the default Python, in Tumbleweed you can also find other
supported Python interpreters. Right now you can find all the Python
versions currently supported by the Python Foundation, from 3.8 to
3.11.&lt;/p&gt;
&lt;p&gt;For Python 3.8 you'll only find the interpreter, because the python
modules are not built anymore, but for all the other versions you can
find almost the same modules.&lt;/p&gt;
&lt;p&gt;All python modules that provide binaries uses the
&lt;code&gt;update-alternatives&lt;/code&gt;, so you can configure in your system the version
that you want to use as default. For example, if you want to use the
&lt;code&gt;3.9&lt;/code&gt; version of &lt;code&gt;poetry&lt;/code&gt;, having installed different versions you can
decide what &lt;code&gt;/usr/bin/poetry&lt;/code&gt; points to:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python311-poetry&lt;span class="w"&gt; &lt;/span&gt;python39-poetry
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;update-alternatives&lt;span class="w"&gt; &lt;/span&gt;--config&lt;span class="w"&gt; &lt;/span&gt;poetry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;/usr/bin/python3&lt;/code&gt; is a link provided by the default python package,
so you can't modify with &lt;code&gt;update-alternatives&lt;/code&gt;, so if you want to use
a different python version, make sure to do the correct call with the
full name &lt;code&gt;python3.9&lt;/code&gt;, and use the correct shebang in your python
scripts, for example &lt;code&gt;#!/usr/bin/env python3.9&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;What happens when default changes?&lt;/h2&gt;
&lt;p&gt;This way of distributing Python interpreter and modules is useful,
because you don't need to update your software to work with the latest
Python version, if your software requires another version, you can just
install and continue using it, even on a bleeding-edge distribution
like Tumbleweed.&lt;/p&gt;
&lt;p&gt;But this method has some problems. When the default Python interpreter
is changed in the distribution, all packages that depends on &lt;code&gt;python3&lt;/code&gt;
will be updated, and that works correctly. But if you have installed
some python module using the &lt;code&gt;python3&lt;/code&gt; prefix, that package, and all
dependencies, is not updated automatically.&lt;/p&gt;
&lt;p&gt;For example, if you installed &lt;code&gt;python3-poetry&lt;/code&gt; when &lt;code&gt;python3.10&lt;/code&gt; was
the default system, and then the distribution updates the system
Python to &lt;code&gt;python3.11&lt;/code&gt;, you don't get the &lt;code&gt;python311-poetry&lt;/code&gt; package
by default, you'll need to install it again. This could break you
software, because if you use &lt;code&gt;python3&lt;/code&gt; and the dependencies are not
updated, you'll find that some dependencies are not installed after
updating.&lt;/p&gt;
&lt;p&gt;For that reason, when the default python is changed in Tumbleweed, if
you've software that rely on &lt;code&gt;python3&lt;/code&gt; you should make sure to install
dependencies again by hand. And also you can do a cleanup and remove
all old version packages that you don't need anymore.&lt;/p&gt;
&lt;p&gt;If you just want the latest version you can just do all at once with a
simple script like this:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c1"&gt;# up-py-tw.sh&lt;/span&gt;

&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-lt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Usage:   up-py-tw.sh FROM TO&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;example: up-py-tw.sh 310 311&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Updating python packages from &lt;/span&gt;&lt;span class="nv"&gt;$FROM&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="nv"&gt;$TO&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="nv"&gt;OLDP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;search&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;-*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;--lines&lt;span class="w"&gt; &lt;/span&gt;+4&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;--delimiter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--fields&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;NEWP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OLDP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/python&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/python&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/g&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;

sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$NEWP&lt;/span&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OLDP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should verify what will be installed and what will be removed to
make sure that just the python related packages are removed. It's
possible that other packages depend on a python version that's older
than the system one and that's okay.&lt;/p&gt;
&lt;h2&gt;Beta version (3.12.0b4)&lt;/h2&gt;
&lt;p&gt;In Tumbleweed, right now you can find all the supported Python
versions, but it's not just that. At this moment you can also find the
beta version of the next Python interpreter.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python312
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So if you are adventurous and want to test some new feature in the
next Python release, you can do it with the version provided there.
This version could also be used by openSUSE packagers to test the
packages before the Python version is released so it allow us to
prepare everything for the release and it could be in the distribution
earlier and more tested.&lt;/p&gt;
&lt;h2&gt;Development&lt;/h2&gt;
&lt;p&gt;All this multiple python versions is done at distribution level and
usually there's only one source package that produces the
&lt;code&gt;python39-foo&lt;/code&gt;, &lt;code&gt;python310-foo&lt;/code&gt; and &lt;code&gt;python311-foo&lt;/code&gt;. The source
package is usually called &lt;code&gt;python-foo&lt;/code&gt; and can be found in the
&lt;a href="https://build.opensuse.org/project/show/devel:languages:python"&gt;Python devel project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These packages spec uses the python-rpm-macros to generate all the
versions from one source. If you're a packager you can find more
information on the openSUSE wiki about &lt;a href="https://en.opensuse.org/openSUSE:Packaging_Python"&gt;Python Packaging&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 05 Aug 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-08-05:/python-tw.html</guid><category>blog</category><category>software</category><category>suse</category><category>tumbleweed</category><category>gnome</category></item><item><title>rpmlint updates (July 2023)</title><link>https://danigm.net/rpmlint-updates.html</link><description>&lt;p&gt;I'm spending some time every week working in the &lt;a href="https://github.com/rpm-software-management/rpmlint"&gt;rpmlint&lt;/a&gt; project.
The tool is very stable and the functionality is well defined,
implemented and tested, so there's no crazy development or a lot of
new functionalities, but as in all the software, there are always bugs
to solve and things to improve.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/rpmlint-gitg-20230706.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The recent changes applied now in the main branch include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update the usage of &lt;code&gt;rpm&lt;/code&gt; to not use old API.&lt;/li&gt;
&lt;li&gt;Fixes for &lt;code&gt;rpmdiff -v&lt;/code&gt;, check for NULL char, special macros in
   comments and spell checking of description in different languages.&lt;/li&gt;
&lt;li&gt;Move all the metadata from &lt;code&gt;setup.py&lt;/code&gt; to &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Releasing rpmlint as pre-commit hook&lt;/li&gt;
&lt;li&gt;Improvements to the PythonCheck in the dependency checking.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Summer of Code 2023 updates&lt;/h2&gt;
&lt;p&gt;The first month of the Summer of Code has passed and &lt;a href="https://afridhussain.tech"&gt;Afrid&lt;/a&gt; is
doing a great job there. We've now a &lt;a href="https://github.com/rpm-software-management/rpmlint/pull/1079"&gt;draft Pull Request&lt;/a&gt; with some
initial changes that allow us to mock &lt;code&gt;rpm&lt;/code&gt; packages in tests so it's
easier to create new tests without the need of creating a binary
package.&lt;/p&gt;
&lt;p&gt;The first step done was to extend the existing &lt;code&gt;FakePkg&lt;/code&gt; class to
allow us to define package files and some package metadata.&lt;/p&gt;
&lt;p&gt;Now he's working in replacing all of the &lt;code&gt;test_python.py&lt;/code&gt; tests that
uses binaries &lt;code&gt;rpm&lt;/code&gt; to something that doesn't needed.&lt;/p&gt;
&lt;p&gt;The idea is to replace as much tests as possible to reduce the number
of rpm binaries and after that, provide helper functions, decorators
and classes to make it easy to write tests, writing less code.&lt;/p&gt;
&lt;h2&gt;Roadmap&lt;/h2&gt;
&lt;p&gt;In any software project there's always room for improvements, fixes
and enhancements. If the project is there for enough time, it's even
more critical to modernize the code to reduce the technical debt.&lt;/p&gt;
&lt;p&gt;My plan for 2023 is to improve the tests around rpmlint as much as
possible. First with the GSoC project, making it easier to write more
tests, improving the testing tools that we've. And after the summer,
improving the test coverage.&lt;/p&gt;
&lt;p&gt;There's also a tool that shares some of the ideas with rpmlint,
&lt;a href="https://github.com/rpm-software-management/spec-cleaner"&gt;spec-cleaner&lt;/a&gt;, it's also written in Python, so the next step,
after the tests improvements will be to take a deep look into the code
of these two tools and try to integrate in some way. Maybe it's
possible to refactor the common code into an external module, maybe we
can bring some ideas from spec-cleaner to rpmlint. Not sure yet, but
that'll be my next step.&lt;/p&gt;
&lt;p&gt;Don't forget that this is free software, so you can participate too!
If you find any issue in rpmlint or have an idea to improve it, don't
hesitate and &lt;a href="https://github.com/rpm-software-management/rpmlint/issues"&gt;create a new issue&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Thu, 06 Jul 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-07-06:/rpmlint-updates.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><item><title>rpmlint: Google Summer of Code 2023</title><link>https://danigm.net/gsoc-2023.html</link><description>&lt;p&gt;I'm glad to say that I'll participate again in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;, as
mentor. This year will be a bit different from the previous ones,
because I'm not mentoring a GNOME project but a &lt;a href="https://www.opensuse.org/"&gt;openSUSE&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;I started to work at SUSE the past year and with this new job I get
involved in the openSUSE community and I started to contribute to
&lt;a href="https://github.com/rpm-software-management/rpmlint"&gt;rpmlint&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So this summer I'll be mentoring an intern and we'll work on improving
the testing framework of the &lt;a href="https://github.com/openSUSE/mentoring/issues/189"&gt;rpmlint project&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/rpmlint.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The rpmlint project is a command line tool to check rpm packages, the
correctness of these kind of packages and warn the packagers about
usual problems or good practices. It's widely used in all Linux
distributions based on rpm, mainly SUSE and RedHat.&lt;/p&gt;
&lt;p&gt;It is written in Python and uses pytest for testing the code. Right
now there are a lot of .rpm binary packages, to check different
functionality, but that way of testing makes a bit hard to write new
tests and to maintain with changes. The idea of this GSoC project is
to extend the testing framework of rpmlint to support an easy way
of writting tests that doesn't require a real rpm, something that can
mock what it's in the .rpm binary and try to replace some of the
current binary tests with this new mock.&lt;/p&gt;
&lt;p&gt;The selected intern is &lt;a href="https://afridhussain.tech/post/accepted-into-gsoc/"&gt;Afrid Hussain&lt;/a&gt;. He has done some initial
work in the rpmlint project, solving some minor issues and we're now
preparing the work to be done during the GSoC program. I'm sure that
he will be able to achieve great things during these three months, so
I'm looking forward to start to code and see how far can we go.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Tue, 16 May 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-05-16:/gsoc-2023.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><item><title>Twitch: GNOME live coding streaming</title><link>https://danigm.net/twitch.html</link><description>&lt;p&gt;This year I've started with something that I wanted to do since the first COVID
lockdown, but never did. So as a first year resolution I decided to start
streaming and I created my Twitch channel &lt;a href="https://www.twitch.tv/abentogil"&gt;Abentogil&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/twitch-loop.png" /&gt;
&lt;/p&gt;

&lt;p&gt;I've been thinking about streaming since lockdown, when a group of Spanish
people created a nice initiative to teach kids how to code and other tech
stuff. I never participated on that initiative, but it was the seed of this.&lt;/p&gt;
&lt;p&gt;This year I've seen other GNOME streamers doing live coding, like &lt;a href="https://twitch.tv/ebassi"&gt;ebassi&lt;/a&gt;
and &lt;a href="https://www.youtube.com/c/GeorgesStavracas"&gt;Georges&lt;/a&gt; and, at the end, I pluck up the courage to start.&lt;/p&gt;
&lt;h2&gt;The plan&lt;/h2&gt;
&lt;p&gt;I've started with one our at the end of my day, so I'm trying to stream from
Monday to Thursday from 20:00 to 21:00 (CET).&lt;/p&gt;
&lt;p&gt;This routing also will help me to spend more time in free software development
regularly, so not just on weekends or holidays, but a bit of work everyday.&lt;/p&gt;
&lt;p&gt;Right now I've started working on my own projects, like &lt;a href="https://gitlab.gnome.org/danigm/timetrack/"&gt;Timetrack&lt;/a&gt; and
&lt;a href="https://gitlab.gnome.org/danigm/loop/"&gt;Loop&lt;/a&gt;. I've fixed some issues that I had with Gtk4 in Timetrack and I've
started to work on the Loop app to add a MIDI keyboard.&lt;/p&gt;
&lt;p&gt;The other day I discovered the &lt;a href="https://gitlab.gnome.org/bertob/app-ideas/-/issues/58"&gt;Music Grid&lt;/a&gt; app idea in the gitlab and it's
related with the MIDI implementation I've been working on, so the next thing
that I'll do on my streams is to create this music grid widget and add it to
the Loop app, to have a nice Music creation App.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/music-grid.png" /&gt;
&lt;/p&gt;

&lt;h2&gt;The language: Live coding in Spanish&lt;/h2&gt;
&lt;p&gt;I've decided to do the streaming mainly in Spanish. The main reason to do that
is because now you can find documentation and a lot of videos in English, but
for people that doesn't master the English language, it's harder to follow this
content and even harder to participate, to ask or say something.&lt;/p&gt;
&lt;p&gt;Spanish is also my main language, and the idea is not just create tutorials or
something like that, this is just for fun, and if I'm able to create a small
community or influence someone, I want to show that the language is not a
unbreakable barrier.&lt;/p&gt;
&lt;p&gt;I want to make this for the Spanish community, but that doesn't mean that for
some streams I cannot talk in English, all depends on the audience, of course,
if a non Spanish speaker comes and ask something, I'll answer in English and
try to do multilingual stream.&lt;/p&gt;
&lt;p&gt;The International English is the language to use in Free Software, but it's
really important to do not convert that in a barrier, because there are a lot
of different communities and people that don't know the language and the first
contact with something new is always better in your main language. Everything
is easier with help from people that's near to your cultural background.&lt;/p&gt;
&lt;h2&gt;The future&lt;/h2&gt;
&lt;p&gt;Right now I'm working on Loop and every stream is similar, live coding on this
Gtk4 music APP, but in the future I'll do different streams, doing different
things on each week day. These are the current ideas that could be a day on my
stream:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maintenance day: Work on my apps, code review, fixes, releases, and
   development.&lt;/li&gt;
&lt;li&gt;GNOME Love day: Give some love to the GNOME project, look for simple bugs to
   solve in different projects, help with translations, initiatives, and other
   possible one hour task to give some love to the project in general.&lt;/li&gt;
&lt;li&gt;Learning day: Pick some technology and learn by doing, for example, I
   can explore new programming languages writing a simple app, learn about
   Linux writing a driver, learn how to animate with blender, anything new to
   play and discover.&lt;/li&gt;
&lt;li&gt;Newcomers day: Create simple tutorial or introduction to some technology,
   How to write a GNOME Shell extension, how to create a Gtk4 app in python,
   teach to code from zero, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is just a list of ideas, if I discover any other interesting use of this
time and stream, I can do that. The final goal of this is to have fun, and if
someone learns something in the journey, that's even better.&lt;/p&gt;
&lt;p&gt;I'll also upload any interesting stream to &lt;a href="https://www.youtube.com/danigmx"&gt;youtube&lt;/a&gt;, so the good content
could be viewed on demand.&lt;/p&gt;
&lt;p&gt;So if you like this, don't hesitate to view some of the streams and say "Hola":&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;a href="https://twitch.tv/abentogil"&gt;
        &lt;img src="/pictures/twitch.jpg" /&gt;
    &lt;/a&gt;
&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 22 Jan 2022 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2022-01-22:/twitch.html</guid><category>blog</category><category>gnome</category><category>software</category><category>outreach</category><category>twitch</category><category>live coding</category></item><item><title>Loop: A simple music application</title><link>https://danigm.net/loop.html</link><description>&lt;p&gt;In the last year I've seen some &lt;a href="https://www.twitch.tv/leonbratt"&gt;really good musician&lt;/a&gt; that performs all
the instruments in a song with just a loop machine, recording each instrument
one by one in tracks and looping.&lt;/p&gt;
&lt;p&gt;I was thinking that it should be easy to have a desktop application that does
exactly the same, just some tracks to record some sounds and the playback with
a loop option, and that's what I created during this week.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/loop.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://gitlab.gnome.org/danigm/loop/"&gt;Loop application&lt;/a&gt; is just a simple Gtk4 application that uses gstreamer
to record tracks and then you can play each one at the same with or without
loop option. With that, a good musician could create the base melody of the
song and then sign on top of that. Unfortunately, I'm not a good musician, but
I can use this to play around.&lt;/p&gt;
&lt;p&gt;I've just created the &lt;a href="https://github.com/flathub/flathub/pull/2674"&gt;request on flathub&lt;/a&gt; to add the application, so if
everything is okay it will be available there soon, so more people can play
with this awesome toy.&lt;/p&gt;
&lt;p&gt;Right now it has the basic record, play and loop functionality with just four
tracks, so don't expect to have a professional music app (yet). The recording
and play times are not perfect and there's a delay, that's a known issue, but
I'm planning to fix this issue and add more functionality in the future, like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make number of tracks configurable&lt;/li&gt;
&lt;li&gt;Import track from files&lt;/li&gt;
&lt;li&gt;Add a trim slider per track, to be able to adjust the recorder track to loop&lt;/li&gt;
&lt;li&gt;Metronome tick and clock to have a visual reference for recording tracks&lt;/li&gt;
&lt;li&gt;A record button, but export the combination of all tracks and mic to a mp3
   file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And that's all. The logo and design is an initial version done by myself, so if
any designer wants to take a look, all contributions are welcome. And of course
any code contribution is also welcome.&lt;/p&gt;
&lt;p&gt;If you use this application and do some good or fun performance, please, ping
me on social networks and let me know.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 11 Dec 2021 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2021-12-11:/loop.html</guid><category>blog</category><category>gnome</category><category>software</category><category>music</category><category>loop</category></item><item><title>Endless Orange Week: Hack content creators platform (2)</title><link>https://danigm.net/hack-content-creators-1.html</link><description>&lt;p&gt;The past Friday was the last day of the &lt;a href="http://danigm.net/hack-content-creators.html"&gt;Endless Orange Week&lt;/a&gt;. It was a nice
and fun experience, and even if I was not able to do as much as I wanted, we
were able to make something that "works" in the Hack project.&lt;/p&gt;
&lt;h2&gt;The Hack Quest editor&lt;/h2&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/clubhouse-custom-quests-1.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The first step to have custom quests on the Hack app was to complete the
&lt;a href="https://www.inklestudios.com/ink/"&gt;Ink language&lt;/a&gt; support. We started to work on this some time ago, but never
completed the functionality.&lt;/p&gt;
&lt;p&gt;I worked on that the first three days, updating the ink library and building
the missing pieces to be able to load quests from random paths. I've
implemented that in a way that the Hack application is able to receive a path
to a &lt;code&gt;.ink&lt;/code&gt; file, and it's able to build and run the quets.&lt;/p&gt;
&lt;p&gt;The Quests are not just the script, but they have some metadata, like title,
subtitle, description, difficulty and the card image to show on the interface.
To solve that I defined a "custom quest bundle format", that's bassically a
folder with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;questId&lt;/li&gt;
&lt;li&gt;quest.jpg&lt;/li&gt;
&lt;li&gt;metadata.json&lt;/li&gt;
&lt;li&gt;quest.ink&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So I also added the functionality to import a bundle zip file and export with
the quest information.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/clubhouse-custom-quests-2.png" /&gt;
&lt;/p&gt;

&lt;p&gt;I created some command line options to use this new functionality:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ink&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FULL_INK_FILE_PATH&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;import&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PATH_TO_BUNDLE_OR_INK_FILE&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;Import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;export&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;CUSTOM_QUEST_ID&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;Export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;custom&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;quest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Quest creation interface and the Inky Editor&lt;/h3&gt;
&lt;p&gt;The first idea was to try to provide a full quest creation experience in the
app, but that was too much, so we decided to simplify the way to create quests
and depend on the &lt;a href="https://flathub.org/apps/details/com.inklestudios.Inky"&gt;Inky editor&lt;/a&gt; external tool. Manuel Quiñones took some time
to update the flatpak application with the latests ink version, so we can use
to create custom quests.&lt;/p&gt;
&lt;p&gt;The Inky editor provides help about the language, syntax highlighting and a
simple way to test the script, so it's a nice tool. The main problem with this
tool is that it doesn't provide a way to launch it with a file path so it's
not possible to integrate with the Hack app.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/clubhouse-custom-quests-3.png" /&gt;
&lt;/p&gt;

&lt;p&gt;So at the end, the Quest creation dialog is just a way to define the metadata
and to select the Quest ink files from your filesystem. How the ink script is
created is a decision to make for the content creator.&lt;/p&gt;
&lt;h3&gt;The future&lt;/h3&gt;
&lt;p&gt;We've no time to complete all we wanted to do, and I didn't create a new
release, so this new functionality is still not there. But we'll try to do a
release soon.&lt;/p&gt;
&lt;p&gt;Simon is working on some interface improvements and also on a new tutorial
Quest, so we can introduce the Custom Quest creation tool in the same app.&lt;/p&gt;
&lt;h2&gt;The Character editor&lt;/h2&gt;
&lt;p&gt;The other part of this week planning was the character editor. Joana did a
really nice work designing the application, the initial assets and the user
experience, but I had not too much time to work on the implementation.  So I
spent just one day working on this.&lt;/p&gt;
&lt;p&gt;The main idea was to create a new independent app, and then provide a way to
integrate with the Hack application and the custom Quest creation dialog. And
it'll be a simple application so maybe it could be useful or interesting for
other people, it's a fun way to play around and create random faces.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/avatar-creator-1.png" /&gt;
&lt;/p&gt;

&lt;p&gt;We just created the application &lt;a href="https://github.com/endlessm/avatar-creator/"&gt;Avatar Creator&lt;/a&gt;. I created a simple python
Gtk4 application and worked a bit on the basic functionality. So right now it
loads a list of svg assets and provide the 3x3 grid. You can click on a grid
cell and then choose what basic image should go there.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/avatar-creator-2.png" /&gt;
&lt;/p&gt;

&lt;p&gt;I added the initial set of basic images, created by Joana, to create this funny
robot faces, but the format is simple enough to extend with different "avatar
libraries" in the future.&lt;/p&gt;
&lt;p&gt;Right now it's also possible to export to png, so the app is functional, but it
needs a bit more work.&lt;/p&gt;
&lt;p&gt;My idea is to work a bit more in the following weeks, when I have some time, on
weekends or holidays and at some point, publish it in flathub. And lets see if
there are more developers interested on this app so it can grow.&lt;/p&gt;
&lt;p&gt;The application is simple enough to be a good place for GNOME newcomers and it's
also a fun project to work on. A simple toy app to create faces that could
have some potential, some future ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;"Smart" random faces generator&lt;/li&gt;
&lt;li&gt;Configurable grid: Maybe is interesting to make it bigger or smaller to play
   around&lt;/li&gt;
&lt;li&gt;Programmed simple base image manipulations, like rotation, mirror, color&lt;/li&gt;
&lt;li&gt;Animation creation, maybe be able to export to gif&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The Endless Orange Week experience&lt;/h2&gt;
&lt;p&gt;This week was a really nice experience, because we were working in a "personal"
chosen project, that we liked and without the day to day meetings, times
schedules and other related work stuff.&lt;/p&gt;
&lt;p&gt;But that was not all. In Endless we've different teams that work mostly
isolated, because we're working on different fields, we've some overlapping,
but we work day to day as small teams, and this week we were all using the same
slack channel to show our progress, and it was nice.&lt;/p&gt;
&lt;p&gt;Maybe now that we're not a big organization with a lot of workers, we can do
something like this more often, it's always good to know more about other
coworkers and to learn something that maybe it's not related with your main
project, but it could be interesting.&lt;/p&gt;
&lt;p&gt;I'm really happy that we did this Endless Orange Week, it's sad that it ended
too soon, I'm waiting to learn from my coworkers what amazing things they do
during this week and I'm looking forward the next year Orange Week!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Mon, 15 Nov 2021 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2021-11-15:/hack-content-creators-1.html</guid><category>blog</category><category>hack</category><category>endless</category><category>orangeweek</category><category>work</category><category>gnome</category><category>software</category></item><item><title>Endless Orange Week: Hack content creators platform</title><link>https://danigm.net/hack-content-creators.html</link><description>&lt;p&gt;This week (Nov 8 – 12) I am participating in Endless Orange Week, a program
where the entire &lt;a href="https://www.endlessos.org/"&gt;Endless&lt;/a&gt; team engages in projects designed to grow our
collective learning related to our skills, work and mission.&lt;/p&gt;
&lt;p&gt;We propose a project, that could be anything, and then work during the whole
week, without distraction. I've choosed to work on the &lt;a href="https://www.hack-computer.com/"&gt;Hack project&lt;/a&gt;, that's a
really nice project that needs some love, because since the past year, we have
&lt;a href="https://www.endlessos.org/key"&gt;other priorities&lt;/a&gt;, so there's no time to improve the Hack app.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;a href="/pictures/clubhouse.png"&gt;
        &lt;img src="/pictures/clubhouse.png" /&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;The project: Hack content creators platform&lt;/h2&gt;
&lt;p&gt;The Hack application is a "Quest" launcher, and each Quest is an interactive
learning experience, a guided introduction to some technology or topic.&lt;/p&gt;
&lt;p&gt;Quests are just python scripts, with a simple library to expose messages to the
user, ask questions, or wait for desktop events, like launch an application,
focus an application, etc. And all these Quests are inside the application, and
are created by the Hack team and released with a new Hack app flatpak.&lt;/p&gt;
&lt;p&gt;The main idea of the project is to provide a simple Quest editor to allow any
Hack user to create and share their our Quests.&lt;/p&gt;
&lt;p&gt;To have this Hack content creators platform we'll need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To simplify the way we create Quests, instead of a python script, we'll uses
   a Domain Specific Language, called &lt;a href="https://www.inklestudios.com/ink/"&gt;Ink&lt;/a&gt;. We started to work on this, but
   we never ended the support.&lt;/li&gt;
&lt;li&gt;To create the interface to be able to import and export custom Quests, that
   could be zip bundles, with the Ink script and some images.&lt;/li&gt;
&lt;li&gt;To create the interface to write the actual Quests and save or bundle.&lt;/li&gt;
&lt;li&gt;Create some introductory Quest to explain "how to create your own Quests!".&lt;/li&gt;
&lt;li&gt;Create an character editor, to be able to "design" new characters for Quests.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;The Quest editor&lt;/h3&gt;
&lt;p&gt;The Quests will be written using the Ink language, and there's &lt;a href="https://flathub.org/apps/details/com.inklestudios.Inky"&gt;something done before&lt;/a&gt;.
The first idea is to just provide a text editor and some helpful information
about the format, and maybe a button to validate. But if there's time we can
use something advanced or even integrate the &lt;a href="https://flathub.org/apps/details/com.inklestudios.Inky"&gt;Inky&lt;/a&gt; editor.&lt;/p&gt;
&lt;h3&gt;The Character editor&lt;/h3&gt;
&lt;p&gt;Each Quest has a main character, and we've five in the Hack app right now, but
it could be great to be able to define new ones for custom Quests. That's the
idea of this part of the project.&lt;/p&gt;
&lt;p&gt;The initial idea is to have a library of character parts to combine, and the
editor will allow the user to combine this parts and maybe change colors, to be
able to create unique characters for your Quests.&lt;/p&gt;
&lt;h3&gt;The Team&lt;/h3&gt;
&lt;p&gt;I'm not working alone in this "side" project during the Endless Orange Week,
Simon Schampijer and Joana Filizola will be working on this too, so this is a
big task but we've a great team. Let's see how far we are able to go during
just one week.&lt;/p&gt;
&lt;h3&gt;The impact&lt;/h3&gt;
&lt;p&gt;This is just a project to try to keep alive more time the Hack application,
without a lot of effort or a whole team behind it. We are not able to put more
content there periodically, so if there's a way to create new content easily
and (maybe in the future) a way to publish, it'll be possible to create a
community around the project.&lt;/p&gt;
&lt;p&gt;And we have also new possibilities, in the near future, we can add some Hack
content to the Endless Key, and using the Ink language, so this editor could
help to bring more content there easily.&lt;/p&gt;
&lt;p&gt;And the final piece, the Character editor, could be an independent application,
a nice simple application that could be used to create your character for your
profile photo, or to generate random character pics.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Mon, 08 Nov 2021 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2021-11-08:/hack-content-creators.html</guid><category>blog</category><category>hack</category><category>endless</category><category>orangeweek</category><category>work</category><category>gnome</category><category>software</category></item><item><title>Fractal: Refactoring and the review process</title><link>https://danigm.net/gsoc-2020-1.html</link><description>&lt;p&gt;In this year GSoC, &lt;a href="https://aledomu.github.io/gnome/refactoring-fractal-remove-backend-i/"&gt;Alejandro&lt;/a&gt; is working on Fractal, moving code from the
backend to the client, to try to simplify the code used to communicate with the
matrix.org server and maybe in the future we can replace &lt;code&gt;fractal-matrix-api&lt;/code&gt;
with the &lt;a href="https://matrix.org/sdks/#matrix-rust-sdk"&gt;matrix-rust-sdk&lt;/a&gt;. And then we'll have less code in our project to
maintain.&lt;/p&gt;
&lt;p&gt;This is a great work, something needed in a project with a technological debt
of several years. I created this project to learn Rust, and also I was learning
about the matrix protocol during the project build. And other contributors do
the same. So we've been building one thing on top another for a lot of years.&lt;/p&gt;
&lt;p&gt;In this kind of community driven projects it's the way to go. For some time
we've people interested and developers think about the design and start change
some parts or to write new functionality following a new design pattern. But
voluntary developers motivation change in time and they left the project and
the next one continues the work with a different vision.&lt;/p&gt;
&lt;p&gt;It's not something bad, it's the greatness of the open source. Different people
has different motivations to participate in a free software project, and every
contribution is welcome. I'm the maintainer of the project and I've spent a lot
of time building Fractal, but I don't have the same motivation now to work on
the project, to it's good to have other people working on it so it can continue
alive.&lt;/p&gt;
&lt;p&gt;Alejandro is doing a great work and he's not a 4 months contributor. He's
working on the backend refactoring for 2 years now, step by step and he has
plans for the future.&lt;/p&gt;
&lt;p&gt;Refactoring a big project is always hard, because there's a lot of code
movement and always there's the fear to regressions.&lt;/p&gt;
&lt;p&gt;Rust is a great language and it shines when big code refactoring comes to the
scene. If it compiles, you &lt;strong&gt;know&lt;/strong&gt; that there's no memory errors, dangling
pointers and that kind of problems. If it builds it will work.&lt;/p&gt;
&lt;p&gt;But maybe it will work &lt;em&gt;different&lt;/em&gt;, so the review process is needed to ensure
that the application continues working.&lt;/p&gt;
&lt;p&gt;Automated tests are really useful for big code changes and project refactoring,
because you have a quick picture and some certainty that the project is
working. But we don't have tests in fractal :D, so someone should do that.&lt;/p&gt;
&lt;p&gt;So here I am. &lt;a href="https://gitlab.gnome.org/GNOME/fractal/-/merge_requests/581"&gt;Reviewing large MR&lt;/a&gt;, with a lot of lines. At least gitlab
makes this process a bit easier.&lt;/p&gt;
&lt;p&gt;What I'm trying to do in the review process is to just read the whole diff and
check if there's some problem in the code. And after every change, I run the
app and I do some tests, trying to use the functionality that could be broken
by those new changes.&lt;/p&gt;
&lt;p&gt;This takes a lot of time and it's not something fun to do... But someone has to
do that. And during that process, sometimes I learn something new. Reading code
is an interesting task and try to find bugs in code while reading it, is
something useful. To think about that code, what it does and why.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Tue, 30 Jun 2020 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2020-06-30:/gsoc-2020-1.html</guid><category>blog</category><category>gnome</category><category>software</category><category>fractal</category><category>gsoc</category></item><item><title>Fractal: Google Summer of Code 2020</title><link>https://danigm.net/gsoc-2020.html</link><description>&lt;p&gt;I'm glad to say that I'll participate again in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;, as mentor. This
summer we'll try to implement multi-account support in &lt;a href="https://gitlab.gnome.org/GNOME/fractal"&gt;Fractal&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/fractal-gsoc.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The selected student is &lt;a href="https://summerofcode.withgoogle.com/projects/#6726209787920384"&gt;Alejandro Dominguez&lt;/a&gt; (aledomu), that is
collaborating with Fractal since the Seville Hackfest in December 2018, doing
a great work in the backend. Alejandro is young developer with a lot of energy
and ideas, so it's great to have this kind of people working on GNOME.&lt;/p&gt;
&lt;p&gt;I've not spend much time lately developing Fractal, the time and energy is
limited, but I'll try to use this GSoC mentorship to go back to the &lt;strong&gt;active&lt;/strong&gt;
Fractal development. My objective during this summer will be to stabilize,
fix bugs and improve the performance and create a new release at the end of the
GSoC, because we've a lot of new functionality in master, but I didn't spend
the time to do the release.&lt;/p&gt;
&lt;p&gt;The google summer of code is a great opportunity for free software, it give
us a full time working student, during three months, working on free software,
so it's really appreciated in a community where a lot of work is volunteer work.&lt;/p&gt;
&lt;p&gt;There are a total of 14 projects selected for this GSoC round for gnome, you
can take a look to the full list in the &lt;a href="https://summerofcode.withgoogle.com/organizations/5428225724907520/#projects"&gt;GSoC page&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 08 May 2020 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2020-05-08:/gsoc-2020.html</guid><category>blog</category><category>gnome</category><category>software</category><category>fractal</category><category>gsoc</category></item><item><title>Andaluh-rs, a lib to transcript Spanish to Andaluh</title><link>https://danigm.net/andaluh.html</link><description>&lt;p&gt;Spain is a big region with a lot of languages, we've the official one for
the whole region, Spanish or Castilian (es-ES), and other officials languages
spoken in other regions, like the Galician (gl-ES) spoken in Galicia,
the Basque (eu-ES), spoken in the Basque Country, the Catalan (ca-ES)
spoken in Catalonia.&lt;/p&gt;
&lt;p&gt;But we've more languages that doesn't have the same official support, the
Valencian, the Aragonese, the Asturian, &lt;a href="https://en.wikipedia.org/wiki/Languages_of_Spain"&gt;and more&lt;/a&gt;. And also we've some
&lt;strong&gt;dialects&lt;/strong&gt; like the &lt;em&gt;Andalusian&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;All of this languages was discredit during the dictatorship period when the
only official language was the Spanish and the others was treated like
vulgar languages or non educated one, and in some cases the language was
&lt;em&gt;prohibited&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Whe the &lt;em&gt;democracy&lt;/em&gt; arrives, some regions spend a lot of resources trying to
recover the language and are supporting it until now with official institutions
and lessons in the official education system. But in other regions the stigma
continued until today.&lt;/p&gt;
&lt;p&gt;That's the case of the &lt;em&gt;Andalusian&lt;/em&gt;, that right now is not considered a language
but a dialect. In any case, this &lt;em&gt;dialect&lt;/em&gt; is treated as a non cultivated
language, spoken by illiterates. We've a lot of Spanish movies and Series where
the character that spoke &lt;em&gt;Andalusian&lt;/em&gt; was the illiterate, from the countryside
or the servant of the family.&lt;/p&gt;
&lt;h2&gt;Be proud of it&lt;/h2&gt;
&lt;p&gt;In Andalusia we've a lot of culture, literature and music done in &lt;em&gt;Andalusian&lt;/em&gt;,
but we don't have a way to write that and many people try to avoid the &lt;em&gt;acent&lt;/em&gt;
and the local words to look more cultured and because there's no a writing
system, we write in Spanish, it's hard to write lyrics, poetry and other
kind of literature. The Andalusian is not only a way to talk, some words are
short and we've contractions and other vowel sounds so if you write in Spanish,
it's not the same as spoken, some information is missed and for example in music
or poetry the metric doesn't match.&lt;/p&gt;
&lt;p&gt;There's a &lt;a href="https://andaluh.es/"&gt;movement&lt;/a&gt; trying to define a writing &lt;strong&gt;Andalusian&lt;/strong&gt; and promoting the
language, trying to make people proud of it and talk and write without complexes.&lt;/p&gt;
&lt;h2&gt;Translator, here comes the code&lt;/h2&gt;
&lt;p&gt;And there's a &lt;a href="https://github.com/andalugeeks/"&gt;group of developers&lt;/a&gt; that are working in some tools to provide
direct translation from Spanish and other tools to ease the &lt;strong&gt;Andalusian&lt;/strong&gt; writing.&lt;/p&gt;
&lt;p&gt;I like to write code and I'm always happy to find new problems to solve, to learn
new languages, tools and to spend some time trying to code something that I've not
done before. So I decided to write a translator from Spanish to Andaluh using rust,
and I've created the &lt;a href="https://github.com/andalugeeks/andaluh-rs"&gt;andaluh-rs&lt;/a&gt; lib.&lt;/p&gt;
&lt;p&gt;The translator is more or less easy, there're some rules that should be applied
from top to bottom that basically replaces some group of letters. There's a
implementation in &lt;a href="https://github.com/andalugeeks/andaluh-py"&gt;python&lt;/a&gt; that uses regular expressions for that. There're
a lot of regular expressions, so I thougth that it could be easy to use a parser,
so I used the &lt;a href="https://github.com/pest-parser/pest"&gt;pest parser&lt;/a&gt;.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// supress muted /h/&lt;/span&gt;

&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;h&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;H&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;initial_h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;CH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inner_ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;inner_h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="n"&gt;inner_ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;hua&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ua&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;UA&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Ua&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;uA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;hue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ue&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;UE&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Ue&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;uE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;noh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="n"&gt;CH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;letter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;SOI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;?&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;initial_h&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;hua&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inner_ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inner_h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;noh&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I've defined each rule in the pest format, so I've a parser for each rule
and then I can replace the word with the correct replacement.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;h_rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;defs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;H_RULES_EXCEPT&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;initial_h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;inner_h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;keep_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;hue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;keep_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;güe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;hua&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;keep_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;gua&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To simplify the code, I've defined the &lt;code&gt;rule&lt;/code&gt; macro, with the code used in
all rules:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;pat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;replace_exceptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="fm"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AndaluhParser&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_rule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="cp"&gt;$(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$($t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="cp"&gt;$r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;as_str&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_some&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;replace_exceptions_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;repl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outstr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And because the Spanish and the Andaluh languages uses unicode and rust Strings
can not be iterated by &lt;em&gt;unicode&lt;/em&gt;, I've used &lt;code&gt;unicode_segmentation&lt;/code&gt; crate, and
defined some utility macros to get the real String len and to get slices of that
String.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;UnicodeSegmentation&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;graphemes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$end&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cp"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With all this done, we only have to apply all rules, in the correct order,
to the input string so we can get the translated String as output.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;epa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// TODO: escape links&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;h_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;x_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ch_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;gj_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;v_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ll_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;l_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;psico_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;vaf_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;word_ending_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;digraph_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;exception_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;word_interaction_rule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;This code is not the best one, I'm doing a lot of string operations with copies
and clones, I'm sure that anyone with more experience with rust can view a lot
of points where we can optimize this code. At first I thought that the translation
could be done during the parsing, keeping a length to be able to view backward
and forward.&lt;/p&gt;
&lt;p&gt;Maybe it's possible to read char by char, keeping a buffer, and detecting if
we can apply any of the rules with the content in the buffer, but I've based
this lib in the python one, so for me it was easier to translate each regex to
pest regex and then do the same translations in the lib.&lt;/p&gt;
&lt;p&gt;But I still think that there's a better solution for this problem, but some times
it's better to have something that just works instead of a never done best
solution.&lt;/p&gt;
&lt;p&gt;During this process I've learned to use pest and I've been playing a lot with
regular expressions, so it was a fun project.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 06 Jul 2019 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2019-07-06:/andaluh.html</guid><category>blog</category><category>gnome</category><category>software</category><category>andaluh</category><category>language</category></item><item><title>Kung-fu Master, Blindfolded debugging</title><link>https://danigm.net/blindfolded.html</link><description>&lt;p&gt;Recently I've been working in the &lt;a href="https://endlessos.com/"&gt;EOS&lt;/a&gt; update. The change is really big
because EOS has some modifications over the upstream code so there are a lot
of commits applied after the last stable upstream commit.&lt;/p&gt;
&lt;p&gt;EOS 3.5 was based on gnome 3.26 and we are updating to use the gnome 3.32 so
all the downstream changes done since the last release should be rebased on top
of the new code and during this process we refactor the code and commits using
new tools and remove what's now in gnome upstream.&lt;/p&gt;
&lt;p&gt;I've been working in the Hack computer custom functionality that's on top of
the EOS desktop and basically I've been rebasing the code in the shell to
do the Flip to Hack, the Clubhouse, a side component and notification override
to propse hack quests and the wobbly windows effects.&lt;/p&gt;
&lt;p&gt;I've been working mainly with gnome shell and updating javascript code to the
new gjs version, but this was a big change and some rare bugs.&lt;/p&gt;
&lt;p&gt;Here comes the blindfolded debugging. I've a development system with a lot of
changes and a functionality in the gnome shell that depends on different
projects, applications and technologies.&lt;/p&gt;
&lt;p&gt;I don't know the code a lot, because I'm not the one that wrote all of this,
I'm working here since February, so I know a bit how things works, but I'm not
the one who knows everything, there are a lot of rare cases that I don't know
about.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/blindfolded/kungfu.gif" /&gt;
&lt;/p&gt;

&lt;p&gt;I've found and fixes several bugs in different projects, that I don't know about
a lot, during this process. How can I do that? If you are a developer that
write code since a few years maybe you've experienced something similar, I'm
calling this the &lt;strong&gt;blindfolded debugging technique&lt;/strong&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Start to change code without knowing exactly what you're doing, but with a
small feeling that maybe that line is the problem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This technique is only for experienced programmers, as a kungfu master that
put a blindfold in their eyes to fight against an opponent, the developer that
will be brave enough to try this should have a lot of experience or he will fail.&lt;/p&gt;
&lt;p&gt;You're an experienced developer, but you don't know the software that you're
debugging. It doesn't matter. The same way that in a kungfu fight you don't
know your opponent, but almost every fighter has two arms and two legs, so
more or less you'll know that he'll try to punch you or kick you, you've a
clue. As a programmer, every software has an structure, functions, loops...&lt;/p&gt;
&lt;p&gt;No matters who wrote that or how old that code is, if you're an experienced
programmer you'll feel the code and without knowing exactly why or how, you
will be able to look at one line and says: &lt;em&gt;Here you're little buggy friend&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Maybe I'm only trying to justify my lucky with a story to feel better and
say that I'm not a dumb changing random lines to try to find a bug, but I'm
sure that other developers has this feeling too, that feeling that guides you
to the exact problem but that you're not able to rationalize.&lt;/p&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/blindfolded/fight.gif" /&gt;
&lt;/p&gt;

&lt;p&gt;I think that this is the experience, the expertise is your body and your
inner brain doing the work meanwhile you don't need to think about it or
know exactly what you are doing.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sun, 05 May 2019 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2019-05-05:/blindfolded.html</guid><category>blog</category><category>gnome</category><category>software</category><category>debugging</category></item></channel></rss>