Enrico Zinihttp://www.enricozini.org/tags/cazzeggiostaticsite2023-02-17T22:22:04ZEnrico Zini: posts with tag cazzeggioMonitoring a heart rate monitorhttp://www.enricozini.org/blog/2023/debian/monitoring-a-heart-rate-monitor2023-02-17T22:22:04Z2023-02-17T22:22:04Z
<p>I bought myself a cheap wearable Bluetooth LE heart rate monitor in order to
play with it, and this is a simple Python script to <a href="https://github.com/spanezz/heartrate">monitor it and plot
data</a>.</p>
<h2>Bluetooth LE</h2>
<p>I was surprised that these things seem decently interoperable.</p>
<p>You can use <code>hcitool</code> to scan for devices:</p>
<div class="codehilite"><pre><span></span><code><span class="n">hcitool</span> <span class="n">lescan</span>
</code></pre></div>
<p>You can then use <code>gatttool</code> to connect to device and poke at them interactively
from a command line.</p>
<h2>Bluetooth LE from Python</h2>
<p>There is a nice library called <a href="https://github.com/hbldh/bleak">Bleak</a> which
is also packaged in Debian. It's modern Python with asyncio and works
beautifully!</p>
<h2>Heart rate monitors</h2>
<p>Things I learnt:</p>
<ul>
<li>The UUID for the heart rate interface starts with <code>00002a37</code>.</li>
<li>The UUID for checking battery status starts with <code>00002a19</code>.</li>
<li>A longer list of UUIDs is <a href="https://github.com/hbldh/bleak/blob/develop/bleak/uuids.py">here</a>.</li>
<li><a href="https://www.mariam.qa/post/hr-ble/">The layout of heart rate data packets</a>
and <a href="https://github.com/fg1/BLEHeartRateLogger">some Python code to parse them</a></li>
<li><a href="https://help.elitehrv.com/article/67-what-are-r-r-intervals">What are RR values</a></li>
</ul>
<h2>How about a proper fitness tracker?</h2>
<p>I found <a href="https://f-droid.org/packages/de.dennisguse.opentracks/">OpenTracks</a>,
also on <a href="https://f-droid.org/">F-Droid</a>, which seems nice</p>
<h2>Why script it from a desktop computer?</h2>
<p>The question is: why not?</p>
<p>A fitness tracker on a phone is <em>useful</em>, but there are lots of <em>silly</em> things
one can do from one's computer that one can't do from a phone. A heart rate
monitor is, after all, one more input device, and there are never enough input
devices!</p>
<p>There are so many extremely important use cases that seem entirely unexplored:</p>
<ul>
<li>Log your heart rate with your git commits!</li>
<li>Add your heart rate as a header in your emails!</li>
<li>Correlate heart rate information with your work activity tracker to find out
what tasks stress you the most!</li>
<li>Sync ping intervals with your own heartbeat, so you get faster replies when
you're more anxious!</li>
<li>Configure workrave to block your keyboard if you get too excited, to improve
the quality of your mailing list contributions!</li>
<li>You can monitor the monitor script of the heart rate monitor that monitors
you! Forget <a href="https://en.wikipedia.org/wiki/Buffalo_buffalo_Buffalo_buffalo_buffalo_buffalo_Buffalo_buffalo">buffalo</a>,
be your monitor monitor monitor monitor monitor monitor monitor monitor...</li>
</ul>
Boring restaurantshttp://www.enricozini.org/blog/2020/boring-restaurants2020-07-24T10:47:25Z2020-07-24T10:47:25Z
<p>While traveling around Germany, one notices that most towns have a Greek or
Italian restaurant, and they all kind of have the same names. How bad is that
lack of fantasy?</p>
<p>Let's play with <a href="https://overpass-turbo.eu/">https://overpass-turbo.eu/</a>. Select a bounding box and run
this query:</p>
<div class="codehilite"><pre><span></span><span class="x">node</span>
<span class="x"> [cuisine=greek]</span>
<span class="x"> (</span><span class="cp">{{</span><span class="nv">bbox</span><span class="cp">}}</span><span class="x">);</span>
<span class="x">out;</span>
</pre></div>
<p>Export the results as gpx and have some fun on the command line:</p>
<div class="codehilite"><pre><span></span>sed -nre <span class="s1">'s/^name=([^<]+).*/\1/p'</span> /tmp/greek.gpx <span class="se">\</span>
<span class="p">|</span> sed -re <span class="s1">'s/ *(Grill|Restaurant|Tavern[ae]) *//g'</span> <span class="se">\</span>
<span class="p">|</span> sort <span class="p">|</span> uniq -c <span class="p">|</span> sort -nr > /tmp/greek.txt
</pre></div>
<p>Likewise, with Italian restaurants, you can use <code>cuisine=italian</code> and something like:</p>
<div class="codehilite"><pre><span></span>sed -nre <span class="s1">'s/^name=([^<]+).*/\1/p'</span> /tmp/italian.gpx <span class="se">\</span>
<span class="p">|</span> sed -re <span class="s1">'s/ *(Restaurant|Ristorante|Pizzeria) *//g'</span> <span class="se">\</span>
<span class="p">|</span> sort <span class="p">|</span> uniq -c <span class="p">|</span> sort -nr > /tmp/italian.txt
</pre></div>
<p>Here are the top 20 that came out for Greek:</p>
<div class="codehilite"><pre><span></span> 162 Akropolis
91 Delphi
86 Poseidon
78 Olympia
78 Mykonos
78 Athen
76 Hellas
74 El Greco
71 Rhodos
57 Dionysos
53 Kreta
50 Syrtaki
49 Korfu
43 Santorini
43 Athos
40 Mythos
39 Zorbas
35 Artemis
33 Meteora
29 Der Grieche
</pre></div>
<p>Here are the top 20 that came out for Italian, with a sadly ubiquitous
franchise as an outlier:</p>
<div class="codehilite"><pre><span></span> 66 Vapiano
64 Bella Italia
59 L'Osteria
54 Roma
43 La Piazza
38 La Dolce Vita
38 Dolce Vita
35 Italia
32 Pinocchio
31 Toscana
30 Venezia
28 Milano
28 Mamma Mia
27 Bella Napoli
25 San Marco
24 Portofino
22 La Piazzetta
22 La Gondola
21 Da Vinci
21 Da Pino
</pre></div>
<p>One can play a game while traveling: being the first to spot a Greek or Italian
restaurant earns more points the more unusual its name is. But beware of being
too quick! If you try to claim points for one of the restaurant with the top-5
most common names, you will actually will actually lose points!</p>
<p>Have fun playing with other combinations of areas and cuisine: the
<a href="https://wiki.openstreetmap.org/wiki/Overpass_API/Language_Guide">Overpass API</a>
is pretty cool!</p>
<p><strong>Update</strong>:</p>
<p>Rather than running xml through sed, one can export geojson, then parse it with the excellent <a href="https://github.com/stedolan/jq">jq</a>:</p>
<div class="codehilite"><pre><span></span>jq -r <span class="s1">'.features[].properties.name'</span> italian.json <span class="se">\</span>
<span class="p">|</span> sed -re <span class="s1">'s/ *(Restaurant|Ristorante|Pizzeria) *//g'</span> <span class="se">\</span>
<span class="p">|</span> sort <span class="p">|</span> uniq -c <span class="p">|</span> sort -nr > /tmp/italian.txt
</pre></div>
Opinion Sorthttp://www.enricozini.org/blog/2019/opinion-sort2019-07-27T09:29:21Z2019-07-27T09:29:21Z
<blockquote>
<p>«Bullshit is unavoidable whenever circumstances require someone to talk
without knowing what he is talking about. Thus the production of bullshit is
stimulated whenever a person’s obligations or opportunities to speak about
some topic are more excessive than his knowledge of the facts that are
relevant to that topic.</p>
<p>This discrepancy is common in public life, where people are frequently
impelled— whether by their own propensities or by the demands of others—to
speak extensively about matters of which they are to some degree ignorant.</p>
<p>Closely related instances arise from the widespread conviction that it is the
responsibility of a citizen in a democracy to have opinions about everything,
or at least everything that pertains to the conduct of his country’s affairs.</p>
<p>The lack of any significant connection between a person’s opinions and his
apprehension of reality will be even more severe, needless to say, for
someone who believes it his responsibility, as a conscientious moral agent,
to evaluate events and conditions in all parts of the world.»</p>
<p>(From <a href="https://en.wikipedia.org/wiki/On_Bullshit">Harry G. Frankfurt's <em>On Bullshit</em></a>)</p>
</blockquote>
<h2>Opinion Sort</h2>
<p>In a world where it is more important to have a quick opinion than a thorough
understanding, I propose this novel sorting algoritihm.</p>
<div class="codehilite"><pre><span></span><span class="k">def</span> <span class="nf">opinion_sort</span><span class="p">(</span><span class="nb">list</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Any</span><span class="p">],</span> <span class="n">post</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[</span><span class="n">List</span><span class="p">]):</span>
<span class="sd">"""</span>
<span class="sd"> list: a list of elements to sort in place</span>
<span class="sd"> post: a callable that requires a sorted list as input and does</span>
<span class="sd"> proper error checking, as they should do</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="nb">list</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">></span> <span class="nb">list</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">swap</span><span class="p">(</span><span class="nb">list</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">list</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># Assert opinion: "It is a sorted list!"</span>
<span class="n">post</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
<span class="k">except</span> <span class="n">NotSortedException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="c1"># Someone disagrees, and they have a good point</span>
<span class="n">swap</span><span class="p">(</span><span class="nb">list</span><span class="p">[</span><span class="n">e</span><span class="o">.</span><span class="n">unsorted_idx_1</span><span class="p">],</span> <span class="nb">list</span><span class="p">[</span><span class="n">e</span><span class="o">.</span><span class="n">unsorted_idx_2</span><span class="p">])</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">break</span>
<span class="c1"># The list is now sorted, and the callable has to agree</span>
</pre></div>
<p>This algorithm is the most efficient sorting algorithm, because it can sort a
list by only looking at the first two elements.</p>
Fiori in primaverahttp://www.enricozini.org/blog/2017/fiori-in-primavera2017-03-19T11:25:35Z2017-03-19T11:25:35Z
<img alt='' width='480' height='360' src='http://www.enricozini.org/blog/2017/fiori-in-primavera-small.jpg'></img>
<h2>Poesia: "Fiori in primavera"</h2>
<p>Se vuoi portarmi dei fiori in primavera</p>
<p>Portami dei carciofi</p>
<p>Che ce li facciamo a fettine sottili</p>
<p>Saltati nell'aglio</p>
<p>E con gli scarti</p>
<p>Facciamo il risotto</p>
<p><img alt="" src="http://www.enricozini.org/blog/2017/fiori-in-primavera.jpg" srcset="http://www.enricozini.org/blog/2017/fiori-in-primavera-medium.jpg 600w, http://www.enricozini.org/blog/2017/fiori-in-primavera-small.jpg 480w, http://www.enricozini.org/blog/2017/fiori-in-primavera-thumbnail.jpg 128w, /blog/2017/fiori-in-primavera.jpg 800w"></p>
Non importa che mi dai del voihttp://www.enricozini.org/blog/2014/non-importa-che-mi-dai-del-voi2014-12-19T14:55:20Z2014-12-19T14:55:20Z
<blockquote>
<p>Dai, non importa che mi dai del voi</p>
<p>In che senso?</p>
<p>Eh, mi dici sempre "voi informatici", "voi tecnici", "voi..."</p>
</blockquote>
Spelling a chilometri zerohttp://www.enricozini.org/blog/2014/spelling-km-zero2014-01-03T23:38:16Z2014-01-03T23:38:16Z
<p>Lo spelling internazionale è troppo
<a href="http://www.lercio.it/lo-spelling-diventa-internazionale-e-domodossola-fa-ricorso/">globalizzato</a>,
e volete recuperare un attimo la dimensione del posto dove siete nati e
cresciuti?</p>
<p>Da oggi c'è questo script che fa per voi: gli dite dove abitate, e lui
vi crea lo spelling a chilometri zero.</p>
<div class="codehilite"><pre><span></span>$ git clone git@gitorious.org:trespolo/osmspell.git
$ <span class="nb">cd</span> osmspell
$ ./osmspell <span class="s2">"San Giorgio di Piano"</span>
<span class="m">1</span>: San Giorgio di Piano, BO, EMR, Italia
<span class="m">2</span>: San Giorgio di Piano, Via Codronchi, San Giorgio di Piano, BO, EMR, Italia
<span class="m">3</span>: San Giorgio Di Piano, Via Libertà, San Giorgio di Piano, BO, EMR, Italia
Choose one: <span class="m">1</span>
Center: <span class="m">44</span>.6465332, <span class="m">11</span>.3790398
A Argelato, Altedo
B Bentivoglio, Bologna, Boschi
C Cinquanta, Castagnolo Minore, Castel Maggiore, Cento
D Dosso
E Eremo di Tizzano
F Funo di Argelato, Finale Emilia, Ferrara, Fiesso
G Gherghenzano, Galliera, Gesso
I Il Cucco, Irnerio, Idice
L Località Fortuna, Lovoleto, Lippo
M Malacappa, Massumatico, Minerbio, Marano
N Navile
O Osteriola, Ozzano dell<span class="err">'</span>Emilia, Oca
P Piombino, Padulle, Poggio Renatico, Piave
Q Quarto Inferiore, Quattrina
R Rubizzano, Renazzo, Riale
S San Giorgio di Piano, Saletto
T Torre Verde, Tintoria, Tombe
U Uccellino
V Venezzano Mascarino, Vigarano Mainarda, Veduro
X XII Morelli
Z Zenerigolo, Zola Predosa
</pre></div>
<p>I dati vengono da <acronym title="Ozzano Sangiorgio Minerbio">OSM</acronym>,
e lo script è un ottimo esempio di come usarne
la <a href="http://wiki.openstreetmap.org/wiki/Nominatim">API di geolocazione</a> (veloci)
e la <a href="http://wiki.openstreetmap.org/wiki/Xapi">API di query geografica</a> (lenta).</p>
<p><strong>Update:</strong> source code is now <a href="https://github.com/spanezz/osmspell">here</a>.</p>
Poesia: "Lavatrice"http://www.enricozini.org/blog/2013/poesia-lavatrice2013-12-03T21:32:23Z2013-12-03T21:32:23Z
<blockquote>
<p>Pensavo fosse pail,</p>
<p>invece ora è feltro.</p>
</blockquote>
Shopshttp://www.enricozini.org/blog/2013/shops2013-12-02T13:07:58Z2013-12-02T13:07:58Z
<p>Christmas songs should only ever be played on Christmas day.</p>
<p>In church.</p>
<p>At midnight.</p>
<p>Unless I happen to be there.</p>
Airportshttp://www.enricozini.org/blog/2013/loncity2013-11-22T17:58:00Z2013-11-22T17:58:00Z
<img alt='' width='480' height='155' src='http://www.enricozini.org/blog/2013/loncity-small.jpg'></img>
<p><img alt="" src="http://www.enricozini.org/blog/2013/loncity.jpg" srcset="http://www.enricozini.org/blog/2013/loncity-medium.jpg 600w, http://www.enricozini.org/blog/2013/loncity-small.jpg 480w, http://www.enricozini.org/blog/2013/loncity-thumbnail.jpg 128w, /blog/2013/loncity.jpg 800w"></p>
<p>In the airport, we are not travellers. We are <em>a captive audience with dwell
time</em>.</p>
<p>In other words, suckers stuck in a room where the only pastime provided is
spending money and staring at advertisements selling advertisement space in
rooms full of suckers like them.</p>
Explanation of umarellhttp://www.enricozini.org/blog/2013/debian/umarells2013-09-20T11:27:07Z2013-09-20T11:27:07Z
<blockquote>
<p><strong>Umarell</strong> /uma'rɛl/ <em>(oo-mah-rell)</em>, n; pl. <em>Umarells</em>. People in a community who
offer all sorts of comments to those who are trying to get some work done,
but who are not doing any work themselves.</p>
</blockquote>
<h2>Etymology and further details</h2>
<p><em>Umarell</em> is a word that entered Italian slang in Bologna and is spreading to
nearby towns, occasionally even across Italy. It comes from the
<a href="http://en.wikipedia.org/wiki/Bolognese_dialect">Bolognese</a> for "cute/odd
little man".</p>
<p>"Umarells" are those people, usually retired men, who spend time watching
construction works, often holding their hands behind their back, occasionally
commenting on what is going on, sometimes trying to tell the workers what to
do.</p>
<p>It's easy to find <a href="http://3.bp.blogspot.com/_XYd_GNd36go/TTRuNXLWuuI/AAAAAAAAAE4/ieMmMiW6ZJo/s320/Umarell.jpg">examples</a>
<a href="http://www.informarexresistere.fr/wp-content/uploads/2011/10/umarell.jpg">on the</a>
<a href="http://www.newhyronja.it/umarells/902.jpg">internet</a>; the word was popularised
by a <a href="http://umarells.wordpress.com/">blog</a> collecting photos, which has even
been published into <a href="http://www.amazon.it/Umarells-Danilo-Masotti/dp/8883425413">a book</a>.</p>
<p>With some Italian Debian friends, we realised that <strong>umarell</strong> is the perfect
word to describe those people in a community, who offer all sorts of comments
to those who are trying to get some work done, but who are not doing any work
themselves.</p>
<p>I think that it is a word that fits perfectly, and since I'm likely going to
use it blissfully anywhere, here is a page that temporarily explains what it
means until the Oxford English Dictionary picks it up.</p>
Yet another Ubuntu anecdotehttp://www.enricozini.org/blog/2011/debian/yaua2011-01-15T09:35:36Z2011-01-15T09:35:36Z
<p><a href="http://netsplit.com/2011/01/11/leaving-canonical/">Some</a>
<a href="http://oskuro.net/blog/freesoftware/new-project-to-discuss-2011-01-14-20-19">posts</a>
on planet made me remember of a little Canonical-related story of mine.</p>
<p>Many years ago I shortly contracted for Canonical. It was interesting and fun.</p>
<p>At the time I didn't have any experience of being temporarily hired by a foreign
company, so I rang my <a href="http://www.nidil.cgil.it/">labour union</a> to get an
appointment, to make sure with them that everything was allright.</p>
<p>The phone call went more or less like this:</p>
<p>Me:</p>
<blockquote>
<p>Hello. I have received this contract for temporary employment by a foreign
company and I wondered if I could book an appointment to come show it to you
to see if it's all ok.</p>
</blockquote>
<p>Their answer rather cut me short:</p>
<blockquote>
<p>Hi. Be careful! People get temporary employment from obscure companies with
the headquarters, like, in the Isle of Man, they do the job, the company
disappears and they never get paid. There's bad stuff out there!</p>
</blockquote>
<p>I looked at the contract, the heading said something like "Canonical ltd,
Douglas, Isle of Man".</p>
<p>I was <em>certain</em> that the union people would have <em>never</em> understood what was
going on. I politely thanked them for their time and hung up. However, to this
day I still regret that I didn't insist:</p>
<blockquote>
<p>Uh, yes, the company is indeed in the Isle of Man. But what if I told you
that it's owned by an <em>astronaut</em>?</p>
</blockquote>
<p>I just signed the contract and had a good time.</p>
Mailman defaultshttp://www.enricozini.org/blog/2010/cazzeggio/mailman-defaults2010-10-01T10:03:53Z2010-10-01T10:03:53Z
<p><img alt="" src="http://www.enricozini.org/blog/2010/cazzeggio/mailman-chance.png" srcset="http://www.enricozini.org/blog/2010/cazzeggio/mailman-chance-thumbnail.png 128w, /blog/2010/cazzeggio/mailman-chance.png 204w"></p>
My rule to see if a framework is worth of attentionhttp://www.enricozini.org/blog/2010/cazzeggio/when-a-framework-is-worth-of-any-attention2010-08-04T13:32:24Z2010-08-04T13:32:24Z
<p>I came up with a little rule:</p>
<blockquote>
<p><em>In order to be worth of any attention, a framework must be stable enough that I can charge money to train people to use it.</em></p>
</blockquote>
<p>This probably applies to other kinds of software stacks, libraries, development
environments and, well, to most software applications.</p>
<p>In the context of python web frameworks, this means that:</p>
<ul>
<li>If it changes API all the time it is not worth of attention, because my
customers won't get value for their money, as they'd continuously need
retraining and rewriting their software.</li>
<li>If I see lots of DeprecationWarnings it is not worth of attention, because
my customers will see them and blame me for teaching them deprecated stuff.</li>
<li>If fixes for bugs affecting the stable version are only distributed "in a
recent git" or "in the next development version", and they are not
backported into a new bugfix-only stable release, then it is not worth of
attention, because:<ul>
<li>my customers' business is to develop their own products based on the
framework.</li>
<li>My customers' business is not to be maintaning in-house stable updates
of the framework. Although if the framework's community is nice enough
they might end up giving a hand.</li>
</ul>
</li>
<li>If it requires virtualenv or can only be obtained through easy_install it is
not worth of attention, because:<ul>
<li>my customers are not interested in maintaning custom deployment
environments over time.</li>
<li>My customers are not interested in tracking each and every single
library's upstream development to keep their production system free of
bugs.</li>
<li>My customers are used to getting software through a proper distribution
which also takes care of security updates.</li>
<li>I am paid to teach them how to use a framework, not a custom python-only
package management system.</li>
<li>In my experience, if distributions have trouble keeping packages up to
date, upstream is doing <a href="http://www.mail-archive.com/python-dev@python.org/msg47681.html">something fundamentally wrong</a>.</li>
</ul>
</li>
</ul>
<p>In light of this rule, I regret to notice that I see very few python web
frameworks worth of any attention.</p>
On python stable APIshttp://www.enricozini.org/blog/2010/cazzeggio/stable-apis2010-07-19T14:14:25Z2010-07-19T14:14:25Z
<blockquote>
<p>There is a theory which states that if ever anyone discovers exactly what the
Universe is for and why it is here, it will instantly disappear and be
replaced by something even more bizarre and inexplicable.</p>
<p>There is another theory which states that this has already happened.</p>
</blockquote>
<p>In Debian testing:</p>
<div class="codehilite"><pre><span></span>/usr/lib/python2.6/dist-packages/sqlalchemy/types.py:547: SADeprecationWarning: The Binary type has been renamed to LargeBinary.
</pre></div>
<p>In Debian Lenny:</p>
<div class="codehilite"><pre><span></span><span class="ne">ImportError</span><span class="p">:</span> <span class="n">cannot</span> <span class="kn">import</span> <span class="nn">name</span> <span class="nn">LargeBinary</span>
</pre></div>
<p>I was starting to think that SQLAlchemy wasn't too bad, since I've been using
it for 6 months and I haven't seen its API change yet.</p>
<p>But there it is, a beautiful reminder that SQLAlchemy, too, is part of the
marvelously autistic Python ecosystem.</p>
On software modularityhttp://www.enricozini.org/blog/2010/cazzeggio/on-software-modularity2010-06-23T15:50:27Z2010-06-23T15:50:27Z
<p>Software modularity is good. You take many modular, reusable components and you
join them together to create a bigger software that is more than the sum of its
parts:</p>
<p><img alt="" src="http://www.enricozini.org/blog/2010/cazzeggio/voltron.jpg" srcset="http://www.enricozini.org/blog/2010/cazzeggio/voltron-thumbnail.jpg 128w, /blog/2010/cazzeggio/voltron.jpg 317w"></p>
<p>But what happens if you try to put together all sorts of modular parts, each
independently designed by a smart person who believes that their way of doing
things is the best in the world?</p>
<p><img alt="" src="http://www.enricozini.org/blog/2010/cazzeggio/frankrobot.jpg" srcset="http://www.enricozini.org/blog/2010/cazzeggio/frankrobot-thumbnail.jpg 128w, /blog/2010/cazzeggio/frankrobot.jpg 358w"></p>
<p>It's not exactly easy to save the world in <em>that</em>.</p>
<p>This post has been brought to you after a lot of paid work on Python, WSGI and
all those sorts of mini/midi/maxi/meta/macro frameworks people built with them,
that always look really, really cool until you actually start to use them for
getting a serious job done.</p>