I often find myself writing some small tool where I need to select a file
or other string. I could do so from the command line, adding some mechanism
to add command line completion, but most of the time, I reach for
fzf. The program takes a list of strings
from STDIN. It displays them as a list and allows me to select an item with
the cursor keys, and to filter the list by typing any sequence of characters.
The searching is fuzzy. It filters the list by any string that contains the
typed characters in sequence.For the example below, I'm listing files in a
directory. There is a file named with an umlaut, hätte.test.

When filtering the list, fzf will ignore
any diacritics in the filename, so typing ha filters the list down to
Changes and hätte.test.

Typing an actual umlaut there respects the diacritics and thus filters the
list immediately down to hätte.test.

In other situations, I can't readily shell out to fzf. Maybe because it is
in a web context or somewhere where I don't want to install fzf. For that
situation, I wrote (and now released)
String::FuzzyMatch. The module
provides a class where you can do such fuzzy filtering and highlighting
on your strings.
my $filter = String::FuzzyFind->new(
highlight_start => '[',
highlight_end => ']',
);
$filter->filter( 'ab', ['aab','abc','acb','cba','aaa', 'abab'] );
# ['aab','abc','acb','abab' ]
# HTML highlighting
my $html = String::FuzzyFind->new(
highlight_cb => sub( $match ) {
return join '',
'<highlight>',
html_escape($match),
'</highlight>',
};
);
$html->highlight( 'ab', 'Now Playing: äbändön' );
# 'Now Playing: <highlight>äb</highlight>'
$html->highlight( 'r&d', 'Welcome to R & D' );
# 'Welcome to <highlight>R</highlight> <highlight>&</highlight> <highlight>D</highlight>'
This approach is quite convenient, because it allows me to have both, a clicky
menu when I'm working on a touch-enabled device, and some quick-access text
entry box where I can type in a short code that matches whatever rare letters
there are in the menu to select an option.
Writing the code was a fun exercise. The nice people at Perlmonks pointed me
towards the appropirate Unicode properties to match or remove respectively.
Then came a quick reminder about NFD, NFC and how I need consistency in my
test suite and my code about when I'm returning what. In the end, I settled
on accepting any encoding but converting and returning the original code
while filtering a list and returning NFD when highlighting a string.
This is a picture I took of one the office building I started working in. The building is on its second general renovation in 20 years. When I started there in 2001, the air condition would struggle to keep the room temperature below 26°C in the summer.

I'm not really deep into class design, Metaobject protocols
and object-oriented programming,
but one feature I've come to like with Perl is using roles to mix-in
methods that are convenient to have but tedious to reimplement ad-hoc. Roles can be implemented
via multiple inheritance, but they (try to) avoid problems by being designed more
around adding self-contained features and not overriding methods in the descendant class.
For example MooX::Role::DBIConnection
gives a class a lazy ->dbh accessor and a nice way to supply database credentials in
the constructor. I'm not claiming that this is the best way to approach this, but it makes
managing the credentials and constructing the database handle very convenient.
{ package My::Example;
use Moo 2;
with 'MooX::Role::DBIConnection';
};
# Lazily connect using the parameters
my $writer = My::Example->new(
dbh => {
dsn => '...',
user => '...',
password => '...',
options => '...',
},
);
my $count = $writer->dbh->selectall_arrayref("select count(*) from mytable")->[0]->[0];
The other thing that roles, or at least Moo::Role
brings to the table is checking that the target class the role is applied to provides
some methods, using the requires keyword. This checks the contract
at compile time instead of needing to exercise the code in the test suite.
I spent some hours revisiting Protocol::Samsung::MDC
to talk to my Samsung EM32DX,
and I reimplemented it using the "new" class
feature, using a Perl-built-in object model. The class feature is still experimental
and the finer points are still being worked on, but for my use-case it worked quite well.
One thing I was missing was a convenient way to emit events from an object. Emitting
events makes for a (IMO) nicer code structure than hooking up callbacks, as I don't have
to set up all callbacks in the constructor, and have a centralized dispatch mechanism
for all events within an object.
package main;
my $foo = My::Thing->new();
$foo->on( myevent => sub( $ev ) {
say "I receivend an event";
});
The basic code is well-tested, originally in Mojo::EventEmitter,
and also available outside of Mojolicious as Role::EventEmitter
and my almost identical MooX::Role::EventEmitter.
The class feature has no provision yet on how to interact with bless-based classes, so reusing these
modules did not work. But copying the code into a class-based module did work, with the
one thing missing - no implicit checking of methods and fields in the target class:
use experimental 'class';
class My::Thing :isa(PerlX::Role::EventEmitter);
use 5.020;
use experimental 'signatures';
sub event_received( $self, $ev ) {
$self->emit( myevent => $ev );
}
...
Maybe one could implement the check for the required members and functions in the
ADJUST phase of the role, but as some day the class feature might gain native
support for roles (or acquire a sibling role keyword), I'm happy to let my test
suite suss out missing methods.
This is a (mostly) random picture I took on one of my photowalks. I like the scene of the lost-but-busy travelling salesman in a brutalist scenery.

Create calendar entries from images

Recently I was at a conference that only published their agenda as a .pdf
file. While I had ample time to manually transcribe the agenda into my
calendar, I wanted a more automated approach, maybe using one of these
newfangled LLM things that are said to be able to extract text from images
based on a simple prompt. Extracting event information from the agenda
would likely also expand well to pictures snapped of concert posters with
my phone camera, just to get a placeholder in my calendar.
If you subscribe to one of the large phone ecosystems, a lot of this functionality already exists.
Google Lens can extract the event dates from pictures for example. But I
don't share my calendar with neither Google nor Apple, so I want a more custom
and more streamlined application.
Since toying around with Net::CalDAV::FindEntry,
I feel familiar enough with CalDAV and Net::CalDAVTalk
to see the import as no problem. The resulting application should be
a two-page basic web application that is reachable via my private network.
Extracting the information is easy by using GLM-4.6V. This means of course sharing
that information with some outside party, but it is only potential events and not my whole
calendar that I'm sharing.
The code also lives on Github,
at least until I move back from Github to self-hosted git repositories.
Application structure
As usual, I wrote the app in Perl, using Mojolicious and I also sprinkled
some HTMX 4 on it, for some interactivity. For example, the image upload
form does not need a second click to actually upload the selected image.
Also, while processing the image with the LLM, the page automatically
refreshes until the results are in.
The steps (and pages) of the app
Upload

Uploading consists of an image and also an optional prompt, to maybe reduce
the number of events created. I found that some nudging for events in the past
or in the future was needed. Uploading the image happens together with
pressing the camera icon. This is not great if you selected the wrong image,
but that happens rarely to me and adding another image isn't that bad.
Processing
I was too lazy to capture the reloading while the extraction is processing.
Results

The results page allows to select events for import and also shows the preview
with title and description. The text recognition isn't always great, but
it is Good Enough for my needs.
At least for debugging, I also wanted a quick way to inspect the generated
.ics calendar data, so I added the "raw" view. This displays the raw
data in all its g(l)ory.

Imported event

After importing, the app also checks my calendar whether the event has already
been imported. This is highly convenient for me to see whether everything
actually worked.
Developing with GLM-5.3
I used GLM-5.3 for parts of the development. I had the model write most of the
test suite and also had it review the HTML and the use of HTMX. It found some
things that would have been annoying for me to find, like double id
attributes on HTML elements, old HTMX attributes that HTMX 4 does not support
anymore.
The fixes the model proposed were also of acceptable quality, but I did not
let it create new features alone. Everything was tightly guided, which results
in code quality that I am content with.