On Culture, Food, Games

Today, I realized I have lived abroad most of my adult life. Yet, I feel as much Italian as I always did.

Culture, in the sense of one’s heritage, language, customs and so on, is such a weird thing. For example, some things we just consider old, or passé, while some others are traditions.

Nobody gives a damn about last year’s clothes, but people will happily wear traditional clothing for special occasions, even tho there’s nothing that makes them particularly different from the clothes of a hundred year before or after.

But some things get frozen in time, and become a paradigm of something, and then people start considering them as the real thing, and deviations are bad.

As an Italian, I see this all the time with food. As most of my countrymen I will be annoyed if I order a carbonara and you put cream and dill in it§. I will cringe at some of the ready-made “italian” monstrosities sold in foreign supermarkets, and of course there’s the Japanese spaghetti napolitana (with ketchup and wurstel) which could make people from Naples punch you§.

But beyond the immediate disapproval, I’m open minded enough to understand that it does not matter. Sure, I would prefer if people named things differently to avoid confusion, but I also understand that our strictness with food is a very modern development. Until a few years ago nobody would give a shit if you made carbonara using pancetta rather than guanciale, for example. The modern pizza napoletana has as little to do with the pizza from 100 years ago as an american deep dish thing, but now the recipe has been written down, and it can’t be changed anymore.

So I see this crystallization process happen in real time, and I find it so, so interesting. But change will happen, anyway.

My kids are italo-hungarian, and mostly I like to think of them as european but it is clear their culture will be mostly magyar. They’ll think it’s normal to take off shoes when you enter someone else’s house§, or that it’s reasonable to have only sweets for a meal§. At the same time they also expect latte e biscotti for breakfast rather than eggs and sausage. And hungarians have decent pizza and coffee these days. The kids will be their own culture and will be alright.

Food is a clear story of homogenization and globalization too: every big city has access to decent curry or sushi these days, if not khinkali and injera§. Yet a bunch of older hyperlocal recipes are disappearing. I have never seen any Italian pastry place make sweet ricotta ravioli as my grandma made them.

And the rest of culture is the same. Probably these days a youngster in Brazil has more shared culture with one in Norway than 20 years ago. They played similar videogames, watched the same blockbusters, have similar comics and books available, hanged around in the same online communities. They may have enjoyed different porn, tho.

But I would guess, when they were little, they played different games, cause children games are not as heavily internationalized yet. But careful, those are being homogenized too. I remember my dad teaching some of the games they played as kids, such as Lippa. I have never seen anyone else play it.

Hungarians kids play a shitty version of hide and seek where you hide and someone finds you and that’s it, you just take turns counting. Italian kids play a hyper-competitive version where once you spot the other person you have to race them to a base point and that captures them, but then the last one to be found still has a chance to free all the others, forcing the counting person to go again. You also have cheats and counter-cheats, such as standing behind a person to touch the base as soon as they are done counting, or having special rhymes that preventively capture those standing behind you. It’s an arms race. It’s a much more entertaining game, and I hope it survives for the sake of future children.

Anyway, culture is drifting, and becoming less diverse overall by becoming more diverse in every single place. Which begs the question: should we care? Should we make an effort to preserve some of our ancestors’ culture, and pass it on to the newest generations? Should we reject novelty? I am pretty sure the last question’s answer is a resounding no, but I think the others are tricky.

For example, should I teach my kids the sort of games my father thought me? What for? Some them made sense in a place when urbanization was mild and dirt roads where more common than asphalt, what would my kids do with them?

I think in a sense it’s always worth preserving something. But we all have limited learning capacity, teaching my kids the child rhymes I knew as a kid would come at the expense of not teaching them something else, and I mean, why would I chose 70 year old italian children rhymes?

When you are physically detached from your parent culture, you feel some need to stick to it, I think. This might be why the USA has this thing of saying “I’m Italian/Irish/Whatever!” meaning “some of my ancestors ended up on these shores coming from there!“. Immigrants felt nostalgia, and passed it on.

It’s also worth considering what is the culture you want to keep or ditch. Italy has a traditionally macho culture, which probably we should not keep in the next century. But it also used to have a very welcoming culture, which we should strive to keep. Hungarians are not particularly friendly and extrovert, we should probably change that. But they also are not very inclined to damage public property, which is good. At the same time, everytime we harmonize the behaviour towards some average expectation of “good” we’re losing something. But I still I hope we won’t have infibulation and the death penalty anywhere in the future. I am not sure what we should do with holy mountains forbidden to women but I have to say, I personally hope they stick around, because I like weird things.

Finally, it’s probably worth thinking about what happens when a culture buds off another one, and becomes separate, and you should stop evaluating it in the same terms. Italian poetry is not read in terms of Latin forms. Espresso should not be considered a bad arab coffee, nor italians should complain about third generation coffee being hipster bait. When does that the split happen? Does it even matter? I have a whole different post to write on english language haiku vs japanese haiku.

I am not sure there’s an answer to any of the questions here, I’ll just keep doing what I feel is best, every day, cause that’s the best I can do. Maybe everyone.

I did build my kids a rubber band gun, as my father did for me. Because it was fun, and because I loved my father and I miss him a lot. Maybe that’s why people stick to their culture, because they loved their parents, and grandparents, and wish they were with them.

Go tell your parents you love them, and your children too. That is some culture all mankind seem to share. And humbly, I think we should keep it.

On Luck

This isn’t a well structured essay, but I haven’t written in a while and I had promised I would, so I’ll put it in words anyway.

Some people claim they have been successful because of hard work, or because they always had a polar star, a dream to follow and did their best to get there.

I believe this is true, at least for some. But I am not one of those.

I am, in some sense, a successful person. I own the place where I live, have a family, and a job that pays well. I can and do travel (worldwide pandemics aside), I have had an education, and as Pearl Jam say,  “I’m a lucky man, to count on both hands the ones I love§.

But I got here by luck, and I didn’t aim, nor worked hard to get here.

You see, I was good in school, mostly because I liked to read, so most of what I was told to study, I already knew. And I was naturally good at math, which meant I basically got through 13 years of school making no efforts to get good grades§.

When I finished high school, I hadn’t decided what to do next, but a friend of mine was going to sign up for the engineering exam (you need to take a small mandatory exam, tho the grades don’t matter) and I went with him.

So, I got in Ingegneria Informatica (Software Engineering, more or less) by chance.

I didn’t really know computers. I had owned a C64 when I was a kid, but it broke before I could learn anything useful, and we had gotten a PC at home only when I was 18 or so, which I used to write some stuff for school, play games, and download pixelated pictures of naked ladies.

I just thought it was a potentially good education for a future job, and I thought AI was cool, so I may have fun studying that§.

But see, at the university I was a terrible student, but I was lucky to become friend with people who loved computers, got me into using IRC, and opened up various avenues of being a script kiddie. I started writing scripts and C, learned linux/*nix stuff, read the stuff from the hacker/FLOSS subculture. It was a lot of fun!

These were the days of 56k internet where you had to pay by minute, and one of my greatest achievements was coming up with a way to steal credentials to connect to the internet to ISP which where unmetered§: scan the ISP subnet for Windows 98 machines with an open SMB share, and copy their credentials§.

Anyway, you know what’s better than a 56k modem? Access to the GARR network, thick fiber cables with speeds you could only dream of.

So me and my friends were spending a lot of time at the department’s computer lab, chatting, playing Worms, and downloading MP3s. We thought to ask the department to set up an IRC server for the university.

They told us we couldn’t do it for the university, but we could do it for the department. They gave us a domain, an old pentium box, an ethernet cable and we were online. Apparently people in dusty university departments are much better at cultivating enterprising people than we give them credit for. And we were lucky, of course.

This was one of the most educational times in my life: we learned how to use Linux and FreeBSD, learned something about security, some more coding. Once, I caught a guy using ettercap in our lab, I wanted to be angry at him because he might be trying to hack into our box, but actually we just became friends, because we found someone else§ had hacked one of the other servers in the network 🙂

So we told the network admins, who were always thankful to us, and then they let us do even more crazy stuff.

Anyway, I met more smart people on the internet and I learned Ruby. I also learned english better by chatting with people on Freenode and reading newsgroups. At some point, I blogged a bit about Ruby, which got me a few odd jobs, because I had been lucky, and I had picked a tech that was growing fast.

Then, in my last year of studies, an internet friend wrote me about the chance to do my master thesis in Ireland, cause I knew Ruby and they used it for some project there. So I got to do my thesis there, in something semantic web adjacent.

At the end of the semester, when I was flying back to Italy, I stopped by in Milan to meet some more internet friends who had a company there, and during some late night chat a guy I just met told me about this startup which had something to do with semantic stuff. And he told the founder of the company, who offered me a job, and I ended up working on cool stuff for a few years. Luck again!

Then, at some point, I was wasting time on the internet, and I think I replied to some guy on HackerNews, and I think he mentioned me to their HR department, and I got another, even better job.

I am intentionally omitting a few of the most fortuitous things that happened between these steps, such as how I got better salaries than I expected, how I met my wife, how I managed to buy an apartment before prices spiked, how we got lucky having two kid etc etc. Unlucky ones too, but those don’t matter.

Still, my point: I got where I am through an incredible list of lucky events, and not aiming to be here at all.

But I don’t mean say one just has to be lucky. One should strive to be ready when luck strikes. Had I not been a good student, I would not have embarked in Engineering studies. Had I not been sociable, I’d not have had such good friends who offered me opportunities. Had I not put in effort to learn Ruby and blog about it I’d not have gotten my first chances, and so on.

As the quote goes

“I’m a greater believer in luck, and I find the harder I work the more I have of it.”

 Thomas Jefferson

But still, Lady Luck lurks behind that too: I would not have had chances to study and own a computer, had I not been born in a family with loving parents, with enough wealth to get me a PC and an education, in a wealthy country, in a time of peace, in a time of economic prosperity, in a region that allows me to travel abroad with ease.

And you know, I just got myself tested for melanoma, and they found me some basal-cell cancer, which is generally not very bad, but can be, and it’s better to treat it sooner rather than later.

I was lucky, I caught it early, cause I went looking for it.

PS: I won’t mention all your names, but all of you folks who have helped me along the journey know who you are, and I will be forever grateful.

Advent of Code 2021: Day 6

I’ve been a bit busy so I skipped doing the tasks in Raku for a couple days, but today’s seemed fun. As usual SPOILERS ahead.

So the problem is basically: you have certain amounts of fish which have a “spawn-timer”, when they reach it they get reset to 6, and create a new fish with a spawn timer set at 8. Given an initial list of fish, we want to know how many fish we have after some days.

You, Clever Reader will certainly have noticed that we have an exponential behaviour: at each step we generate more fish, which will generate more more fish next time, and more more more fish and so on§.

The abstract solution in my mind would be:

  • set the initial values in some container structure
  • call some step function the given amount of days
  • count the total entries in the container

This, more or less

sub solve(@ints, $days) { # ints is something like [1, 2, 3, 3, 1, 4..]
  <whatever>
  step(<whatever>) for ^$days;
  [+] <whatever>;
}

the only interesting thing here is the construct

<do-something> for ^$number

where ^$number is a short form to define a range from 0 to $number and the rest is a short form to do a loop over the right hand size of the for keyword.

Extended this might look like

for 0..$days -> $day { <do-something> }

which I find less entertaining§.

The question to answer next is: what should we use as container?

Raku obviously has a Hash class, and we could initialize it with a default and then iterate over the initial values to build.

> my @ints= [1, 3, 3, 3, 3, 2]
[1 3 3 3 3 2]
> my %counts is default(0);
{}
> %counts{$_}++ for @ints
Nil
> %counts
{1 => 1, 2 => 1, 3 => 4}

The only new bit we see is the is default annotation that builds a container with a default value. But it seemed weird I have to do this, surely Raku has some builtin way to count things, like Ruby’s Enumerable#tally ?

And of course it does. It has More Than One Way To Do It, of course. For example, it provides a Bag class which is an immutable container for counting items, and can be extracted from another sequence trivially

> my @ints = [1, 3, 3, 3, 3, 2]
[1 3 3 3 3 2]
> @ints.Bag
Bag(1 2 3(4))

And a corresponding BagHash which returns a mutable container for counting.

Being a map from Any to Int these also come with a nice default, so when we access a missing item we get 0

> my $bh = @ints.BagHash
BagHash(1 2 3(4))
> $bh{1}
1
> $bh{2}
1
> $bh{3}
4
> $bh{99}
0

Wait, you might say, why are you using a scalar for that object, instead of a hash? Shouldn’t it be %bh rather than $bh?

The answer is: I don’t really know§

> my %bh-as-hash = $bh
{1 => 1, 2 => 1, 3 => 4}
> %bh-as-hash{99}  # no default in the hash!
(Any)
> $bh{99}          # still default in the BagHash!
0
> $bh{99} = 3      # you can update the BagHash
3
> $bh{99}
3
> %bh-as-hash{99}  # but the hash is unaffected
(Any)

You can alternatively use the := binding operator, which performs an assignment without casting:

> my %bh-as-hash-casted := $bh  # notice the representation
BagHash(1 2 3(4) 99(3))
> %bh-as-hash-casted{100} = 100 # it's the same object!
100
> $bh{100}
100

So our full solve can be

sub solve(@ints, $days) {
  my $counts = @ints.BagHash;
  step($counts) for ^$days;
  [+] $counts.values;
}

Now, how does the step function look? It is pretty straightforward, but it has a tricky bit

sub step($counts) {
  my $old = $counts.clone;
  for 8...0 -> $idx {
    $counts{$idx} = $old{$idx + 1};
    if $idx == 0 {
      $counts{8} = $old{0};
      $counts{6} += $old{0};
    }
  }
}

Do you see the… oddity? Look at this:

> for 1..3 -> $i { say $i }
1
2
3
> for 1...3 -> $i { say $i }
1
2
3
> for 3..1 -> $i { say $i }
Nil
> for 3...1 -> $i { say $i }
3
2
1

you cannot iterate in reverse one of those! This is because the .. operator builds a Range while ... builds a Seq. A Range is list of consecutive numbers, with a beginning and an end, while a Seq is something that can be iterated over.

So there are no numbers in an inverse Range, and if you iterate over it you get zero iterations. In my very humble rubyist opinion, this is very confusing™ , but I guess real Raku people are used to it.

Back to our task: of course, the Astute Reader will have noticed we can do this more tersely by simply shifting the array and adding it to itself, and then brining back the extra items. This is a simpler solution, and it’s pretty nice, but we need to build a list rather than a BagHash:.

sub solve2(@ints, $days) {
  my @list is default(0);      # create a list with default value 0
  @list[$_]++ for @ints;       # add all the fish to it
  step2(@list) for ^$days;     # do the steps
  [+] @list;                   # add up the values in the list
}

I have a feeling the first two lines can be collapsed, but I don’t know how, if you have an idea please let me know in the comments.

Our step function becomes very small

sub step2(@counts) {
  @counts.rotate;
  @counts[6] += @counts[8];
}

And honestly, I feel this is as expressive as it can be.

See you next time!

Advent of Code 2021: Day 2

Hello again!

So, Day 2 is not a particularly interesting problem: basically we have a stream of commands, and we need to move a submarine correspondingly, then in the last step we need to compute the product of the depth and horizontal distance

For problem 2, we are going to have “up N”, “down N” and “forward N”, which will respectively affect the aim of the submarine and the position.

This would be pretty trivial to do with a loop and a case/switch statement (which in Raku is called given/when) but I think it’s a cool chance to try out Raku’s multimethods.

A class definition in Raku looks like this

class Sub {
  has $.aim = 0;
  has $.depth = 0;
  has $.horizontal = 0;
  method process($operation, $num) { ... }
}

The $. is a twigil which says “this is a scalar value and it’s private but has accessor methods“.§

Methods (and Routines in general) support multiple dispatch which can happen through class, traits, or any specific attribute of the parameter (see the Signature class). In our case, we want to dispatch through the operation name, so we can do this§

multi method process("forward", $num) {
  ...
}
multi method process("up", $num) {
  ...
}
multi method process("down", $num) {
  ...
}

The actual implementation would be: when we go “up” or “down, we want to alter the aim, and when we go “forward” we move by the given amount horizontally, and by aim * num vertically.

We could alter the values in the given clasinstance, but… it’s uglier! The declared instance variables are immutable, if we want them to be mutable we should have used the rw trait, like this

class Sub {
  has $.aim = 0 is rw;
  has $.depth = 0 is rw;
  has $.horizontal = 0 is rw;
}

Raku is pushing gently against us so we prefer immutability, and who am I to go against that?

EDIT: as noted by mscha in the comments, this is incorrect. The variables are mutable, we could always assign them from within the instance, referring to them with the $! twigil, e.g. $!aim += $num. The is rw only refers to generating setter methods so they’re accessible from outside. Sorry, I’m still learning.

So, each of our process() calls will instead produce a new object by adjusting the current one. Luckily, the language has a pretty nice functionality to help with that: the clone() method accepts an argument to tweak the cloned object, so our code would look like this

class Sub {
  has $.aim = 0;
  has $.depth = 0;
  has $.horizontal = 0;

  multi method process("forward", $num) {
    self.clone(horizontal => $.horizontal + $num, depth => $.depth + $num * $.aim)
  }
  multi method process("up", $num) {
    self.clone(aim => $.aim - $num)
  }
  multi method process("down", $num) {
    self.clone(aim => $.aim + $num)
  }
}

This looks pretty nice to me! Now we only need to plug this into processing the commands. But I thought, well, we decided to be immutable, right? So let’s do this with reduce.

Rather than use the reduce metaoperator like last time, we can use the actual reduce routine. It works similar to other similar function in Python/Ruby/JavaScript/whatever.

my @words = 'day2.txt'.IO.words; # read all words
my @pairs = @words.rotor(2); # pair them up
my $sub = Sub.new # get a sub
<something with $sub and @pairs>.reduce(<block>) # iterate on values

The problem, is that, from what I understand, we cannot pass an initial value (our $sub) as an argument. The way to handle that is through using a Slip.

A Slip allows us to treat a list “as if it was typed there”. For example we can use it to prepend items to a list

> my @list = 1,2,3
[1 2 3]
> my @list2 = 3, @list
[3 [1 2 3]]
> my @list2 = 3, |@list
[3 1 2 3]

Or to use a list as an argument to a multi-argument routine

> my @pair = 1,2
[1 2]
> sub f($a, $b) { say "a: $a, b $b" }
&f
> f @pair
Too few positionals passed; expected 2 arguments but got 1
  in sub f at <unknown file> line 1
  in block <unit> at <unknown file> line 1

> f |@pair
a: 1, b 2

This is akin to the concept of “splat” in ruby, tho it’s somewhat more formalized.

So, we can pass an initial value to reduce by simply prepending it to the commands array:

($sub, |@pairs).reduce(<something>)

something should be a routine that takes two arguments (the accumulator and the next element) and returns a new value for the accumulator. This means it will call process(), and we can once again use a Slip!

($sub, |@pairs).reduce({ $^a.process(|$^b) })

Notice the $^ sourcery: in Raku you can use the ^ twigil to access variables implicitly, they will just be assigned from the arguments in order of definition. This call is effectively equivalent to

($sub, |@pairs).reduce(-> $a, $b { $a.process($b[0], $b[1]) } )

Now we just have to add a method to compute the final value, which is depth * horizontal, and putting all together we get

class Sub {
  has $.aim = 0;
  has $.depth = 0;
  has $.horizontal = 0;

  multi method process("forward", $num) {
    self.clone(horizontal => $.horizontal + $num, depth => $.depth + $num * $.aim)
  }

  multi method process("up", $num) {
    self.clone(aim => $.aim - $num)
  }

  multi method process("down", $num) {
    self.clone(aim => $.aim + $num)
  }

  method value {
    $.horizontal * $.depth
  }

}

my @words = '2.txt'.IO.words;

say (Sub.new, |@words.rotor(2)).reduce({ $^a.process(|$^b) }).value

which I find somewhat nice. I have to say, I still don’t like twigils, and I think I’m missing some way to write objects more tersely, if you know Raku better than me please let me know in the comments.

See you next time, happy hacking!

Advent of Code 2021: Day 1

Oh oh oh! Finally it’s that time of the year again!

I love Advent of Code and I’ve played it with friends and colleagues for years. Usually, I try to solve it in Ruby, since I’m very familiar with it, and so the effort is only on task solving rather than on learning the language and tooling.

But this year, I thought I might do it both in Ruby and in Raku (The Language Formerly Known As Perl 6), by first solving it in Ruby, and then if I have time trying to solve it again in Raku.

So, here’s a quick view of a couple solutions to the problems in Day 1. Stick to the end for the cool solution past the initial line noise 🙂

SPOILERS AHEAD

The first problem is basically: given a list of values, count the number of times they increase

In Ruby 3, this could look like this

def solve1(array)
  array.                # [1, 2, 5, 4]
    .each_cons(2).      # [(1, 2), (2, 5), (5, 4)]
    .count { _1 < _2 }. # 2
end

AKA: get a sliding window of pairs from the initial array, then count the occurrences where the first value in the pair is less than the second value in the pair. Notice the fancy anonymous positional block arguments!

You can do more or less the same in Raku, but I’m not aware of a .count method that takes a block§, but well, we can still do this in three steps:

  • build the sliding window
  • select the items matching the condition
  • get the size of the filtered list

Raku does not have each_slice, instead it has a .rotor method which is a generalization of “iterate and group“, you can define in one go both the size of the group and the offset, i.e.

> my @ints = [1, 2, 3, 4, 5, 6, 7, 8, 9]
[1 2 3 4 5 6 7 8 9]
> @ints.rotor(2)  # group by 2 
((1 2) (3 4) (5 6) (7 8))
> @ints.rotor(2 => 1)  # group by 2, and move by one after 
((1 2) (4 5) (7 8))
> @ints.rotor(2 => -1)  # group by 2, and move back by one after 
((1 2) (2 3) (3 4) (4 5) (5 6) (6 7) (7 8) (8 9))

The actual signature of this method is even more flexible, but this should be enough for us.

To filter we can use .grep, which takes a block. We can do this javacript-like, passing a block with a pointed arrow.§

Then we get the size of the list, which is done with prefix '+' . This is an odd perlism, just accept it.

+ @ints.rotor(2 => -1).grep(-> ($a, $b) { $a < $b })

So, that should work. But at this point it’s just un uglier Ruby! We can do better!

To get there, let’s first see a different way we can build the list of pairs: we can slice the list and merge it with itself, an operation which most languages call zip.

Raku also calls it zip, but it has something cooler than a function: it has a zip metaoperator! §

A metaoperator is basically an operator which takes another operator as argument, and augments it’s behaviour.

The simplest I can think of is the reduce metaoperator. Suppose you want to get the product of all items in a list. You know the operation you want, which is *, and in Ruby, Python, Smalltalk etc.. you would call a method or function called reduce or inject passing a function to it.

In Raku, you apply the prefix reduce metaoperator ([]) to the binary product operator (*):

> [*] [1,2,3]
6

The Zip metaoperator is the same:, it takes a binary operator and returns a binary operator, which applies its argument to items from both sides zipping them up:

> [1, 2, 3] Z* [10, 20, 30]
(10 40 90)

See where we’re going? Yep, we can apply the first metaoperator to the result of the second!§

> [Z*] [1, 2, 3], [10, 20, 30]
(10 40 90)

So, if we want to know “is the item in the left list larger than the corresponding in the right list?” we can just choose the right operator

> [Z>] [1, 2, 3, 1000], [10, 20, 30, 0]
(False False False True)

This means we can apply it to the slices of the original input to obtain a list of Booleans. Then we just have to count them, and you can do this easily by knowing that in Raku you can add Booleans, and they will be treated as 1 and 0.

Do you know how to add up all items in a list? Yep, reduce metaoperator and binary plus (+)!

So the full solution is

[+] [Z<] @ints, @ints[1..*];

Or in even shorter form

[+] [Z<] @ints[*,1..*]

This is at a glance impossible to understand, but it’s actually pretty expressive, and I guess it should get easier with habit, we’ll see 🙂

See you another day, happy hacking!

PS

Problem 2 left as an exercise for the reader. You may want to invest time in learning how to use hyper operators, they are cool!

How to use certbot to get SSL from Let’s Encrypt for EasyWP

I’ve been pretty absent from this blog, so from now I’m going to try to write something at least once a week, on Monday. I may not be able to keep this up, but the first stop to form a habit is to start doing it once.

My requirements for blogging these days are basically: a web UI, I don’t have to maintain deployments, no effort security maintenance, some backups. And frankly the backups are not that important.

Since I already had my domain at Namecheap for a few years, I ended up choosing their EasyWP offering, which is pretty basic but should be fine for now.

While doing this, I took the chance to learn a bit about LetsEncrypt, because it seemed fun.

Let’s Encrypt is a nonprofit Certificate Authority. A CA is basically an entity that can provide a cryptographical proof that you are really you (or rather that some domain like www.riffraff.info is really serving content provided by the owner of www.riffraff.info). For a long time you had to pay for this kind of service, but then Let’s Encrypt appeared and started providing this service for free, with the stated intent of making the internet a safer and better place. Yes, they’re awesome.

The way all this works is by essentially providing some APIs and command line tools that allow you to:

  1. request a certificate for domain.com
  2. get some sort of challenge to prove that you actually own that (e.g. if you really are who you say you are put this string in your DNS records or put this file on your website)
  3. receive a certificate once Let’s Encrypt verifies the challenge is met

The fun part about this is that they will only provide you with short-expiring certificates (2 months), because they want you to automate this. Not automating a renewal will always result in you messing up by forgetting to renew a certificate, like it may happen with anything that you only need to do every few years (checks driving license quickly).

To do that, you can use a wonderful tool called certbot, which has a ton of plugins to be able to interface with many existing services, but does not have direct support for EasyWP/Namecheap.

But fear not! The nice thing about certbot is: you can plug in any kind of script you want, simply providing them as command line options, like this

certbot certonly --manual-auth-hook some-script.sh --manual-cleanup-hook some-other-script.sh -d my.domain.foo

So, how do we do this for EasyWP? Well, there’s no API for domain management but there is SFTP access to upload custom files. This means we can upload a file and use the HTTP verification method.

When you run certbot, it will talk to the Let’s Encrypt servers and receive a challenge, which it will pass through the environment variable $CERTBOT_TOKEN to the manual-auth-hook and manual-cleanu-hook scripts.

The job of your script is thus to get this value and put it in a correspondingly named file in a specified HTTP accessible directory

# authenticator.sh
#!/bin/bash
set -x -e
# assume there is a .well-known/acme-challenge/ directory already
FULL_PATH=".well-known/acme-challenge/$CERTBOT_TOKEN"
echo $CERTBOT_VALIDATION > $FULL_PATH
echo "put -R ./$FULL_PATH /$FULL_PATH" | sftp $SFTP_USER

Notice you will need to provide the sftp password on the command line for this to work. You can use expect, lftp or whatever to automate this properly, this is just for example purposes.

Once this runs, certbot will tell the Let’s Encrypt servers to check if the challenge is met, and if it is it will receive a new certificate, which you can upload through the EasyWP admin UI.

But: what about the cleanup hook? Well, once everything is done, certbot will run the hook to allow you to get rid of the leftover files. Once again, you will have $CERTBOT_TOKEN so your cleanup script can look like this

#!/bin/bash
set -x -e
# keep this challenge around, but make it clear we used it
mv ".well-known/acme-challenge/$CERTBOT_TOKEN"  ".well-known/acme-challenge/used.$CERTBOT_TOKEN"

The full command line would look like this, and notice you can get multiple certs at once

certbot certonly -v --manual --preferred-challenges=http --manual-auth-hook $PWD/authenticator.sh --manual-cleanup-hook $PWD/cleanup.sh -d domain.foo,other.domain.foo

This is of course more work then necessary as you can just pay a bit more to get an SSL certificate from Namecheap, or you can (I think) proxy everything through Cloudflare, but I had fun playing it with it, and I hope this can be useful to someone else 🙂

Summer readings 2021, part 3

Last summary of my summer readings! Fitting, as the summer is over. I did not read a lot of fiction this summer, but hey, I did read some good stuff!

Hearts of Oak

A short novel by Eddie Robson, which features a weird city made of wood in constant expansion. I would be providing spoilers by adding anything else about the plot, so I will just say that it’s pretty original, and I’ve enjoyed it, after a couple false starts (the beginning is somewhat… dull).

Also, I read the MacMillan paperback edition , which for some reason has the most pleasant paper I’ve experienced in a book, feels like silk. OTOH, the cover has a rubbery feel to it, which is kinda annoying.

7/10: I would like to read more of this universe.

The Flying Sorcerers

An anthology of comic fantasy stories by Peter Haining. I acquired this book, together with The Wizards of Odd, simply because it contained some Terry Pratchett. I sort of hoped the rest of the stories would be good.

On average, they’re not. Neither good, nor fun, and they’re not even about flying sorcerers! Yet, a couple of the stories are quite nice.

5/10: there are probably better anthologies in which to spend your time.

The Wind Through the Keyhole

Ah, yes, a Dark Tower novel. You see, I read the first book of the Dark Tower saga, The Gunslinger, about 30 years ago. Most of it in a single afternoon, while going to the dentist. I loved that strange world, mutants, cowboys, and people singing Hey, Jude. When the Man in Black described the Tower, the Beast§ , the Door, my curiosity reached at the stars.

So I proceeded to read the second book immediately after, and I liked it even more.

And… to read the third book I had to wait years! I found it during a summer vacation, in a small library in a mountain town, and when I got it my father wanted to read it too. He loved it, and so every time a new one came out, I would buy it for him, and read it as soon as he finished it. Fun fact, my father had read The Talisman years before, and I had not.

Me, Sai King, and my dad got to the end of the journey many years later, and while I did not love the last book as much as the earlier ones, it was nice to reach it.

Then The Wind Through the Keyhole came out, again many years later. I didn’t read it for ten years, and I only realize as I write, it’s because my dad had died shortly before it came out.

You see, I never got the chance to buy it for him, so I never read it myself.

As Stephen King says

For longtime readers, this book should be shelved between Wizard and Glass and Wolves of the Calla, which makes it, I suppose, Dark Tower 

and content wise it’s also half way: I loved Wizard and Glass, but didn’t particularly enjoy Wolves of the Calla§. And yet, this book is a much better book than the (chronological) last book, maybe because the author wasn’t so worried about dying before finishing the tale.

Reading this book was like going back to my home town, visiting familiar places, meeting the faces I grew up with. Oh, hey Ronald and Jake!

And the book is good. The plot is good, the structure is good, and for once, the ending is good. Also, as Ronald would have it, it seems I remember the face of my father.

8/10: I really wish there was more of this.

Summer readings 2021, part 2 (Comics)

This summer I finally caught up with a bunch of small comics I had kept on the side, but it would make little sense to discuss all those.

Rather, I’d like to mention a few larger things which had been recommended to me. Spoiler: I liked them all.

Providence

This is a completed 12-issue series written by Alan Moore. It’s part of a larger trilogy (with Neonomicon and The Courtyard) of Lovecraft-inspired stories, and I found it quite entertaining. Basically, Moore plays with the Lovecraft material by having the main character encounter various elements of his legendarium, and tying them up with some of Moore’s favorite obsessions.

I think it’s a good comic, but not fantastic, but if you like either Lovecraft, Moore, or In the Mouth of Madness you will enjoy this one too.

6.5/10: bit more than a passing grade, saved by the ending.

Les Indes fourbes

This is a french comic book (and indeed, the only page on wikipedia for it is in french) but I read the version in italian by Rizzoli Lizard (Nelle Indie Perigliose §).

It’s a picaresque graphic novel inspired by an actual novel from the XVII century, and if you like the genre (I do!) you will love it. The plot is good, the characters entertaining, the writing is great.

As a visual thing: this thing is gorgeous. The art is outstanding, rich in details, cleverly structured, and it makes full use of the medium, as a comic book should. Moreover, the edition is a thing of beauty, as a 33.2 x 24.8 (cm) hardcover it might be a bit hard to fit on a shelve, but I’d leave this thing laying around for the sheer joy of looking at it.

9/10: almost perfect.

The Thrilling Adventures of Lovelace and Babbage

This is an odd book, and by the end I enjoyed it but.. I’m unsatisfied. I went into the book expecting to find either a semiserious account of Lovelace & Babbage’s life, or a made up story using them as character.

What the book actually is: a series of episodes, using a cartoon/steampunk/uchronic version of the titular characters, with no actual plot. They’re entertaining, I really like the drawings and I loved the characters, but I’m left wanting more of them.

The other oddity is that each page is about 30% drawings and 70% footnotes explaining them. And each footnote has references to end-of-chapter notes. This is frustrating§ because you have to choose how to read this

  • read comic -> read footnote -> read endnote (requires you to keep a mental stack)
  • read comic -> read footnote; ignore endnotes (never!)
  • read comic -> read footnote; read all endnotes at the end (you will have forgotten what they’re about by the time you read them)

No choice is satisfactory, and I missed the effortless way you can follow up nested footnotes in, say, Terry Pratchett’s Discworld.

At the end of the book you have some appendixes on various things which I found quite dull, but might be of interest to some people.

So, the book is quite interesting, and if the author decided to actually write a steampunk novel using the characters I would run to buy it; but I got to the end of the book feeling that I had a lot of appetizers, and never got the main meal.

7-/10: could be great, but does not deliver.

Summer readings 2021, part 1 (audiobooks)

It’s been so long since I wrote a blog post, and I’m feeling pretty rusty. But there’s no other way to remember how to do something than practice it, so I’m going to attempt to write a new post every week, until the end of the year.

Anyway, I’m sort of short of arguments, but I was lucky enough to be able to have long holidays this summer, so in the footsteps of more successful writers, I’m going to make a short list of the things I read this summer, in the hope they will be useful to other people. But I read a lot! so I’m going to split it. This is the first instalment, talking about stuff I listened to as audiobooks.

The Box: How the Shipping Container Made the World Smaller and the World Economy Bigger

The humble shipping container might not seem like an interesting topic, but it is! The invention/adoption/perfection of the container changed society in a way that few other things did. For example, a whole category of jobs (dockworkers) has been more or less wiped out. Entire cities that relied on people working on interchange traffic lost their income. Worldwide production chains become possible, which in turn enabled “globalization” and all the good and bad that comes with it.

Plus, the book contains pretty fascinating stories of the people who pioneered this, how they succeeded, how they failed. And of those who resisted or embraced the change. And of course, that marvel of human nature: the standardization committee!

There is something to criticize in the book, and it’s the fact that it is, for all its interesting content, far too rich of details. Honestly, it seems like it could have been 6 or 7 blog posts and still be just as informative.

Surely You’re Joking, Mr. Feynman!

I’ve been recommended this book a million times but always put it off. But I recently found out it’s included in the basic Audible membership I have, so I decided to finally listen to it.

Oh, I am so happy I did it. Feynman is hilarious, the list of anecdotes and odd situations which he experience is mindbogglingly, his insights on human nature are pretty enjoyable.

Also, it’s clear he sort of identifies himself as “anti-intellectual” which kinda resonates with my own education, although I think what he really should identify himself as “anti-pomp” (I think he mentions this at some point). It’s easy to mix up the two.

I cannot recommend this book enough. While reading it tho I couldn’t shake the feeling that, had the book been written today, people would have showed up with pitchforks; Feynman is a womanizer of the extreme kind, and plenty of the adventures (e.g. the one that starts with his regular hanging out at some topless diner (!!)) might not mix well with modern sensitivities.

The New Confessions of an Economic Hit Man

This is another of the free books on Audible. The premise is pretty good: a guy who worked for a big corporation tells his story, explaining how there is a corrupt and ever increasing powerful force of “economic hit men”.

Such people in cooperation with the IMF, World Bank, and USAID, manage to bribe, threaten, and coax politicians and government offices from developing countries so that they get loans, the invest money in projects that promise to have grand returns for the population, but end up being realized by the same foreign corporations, which this way manage to syphon back the money, leaving the countries in deeper debt and without having achieved much. Rich people get richer, poor people get poorer, rinse and repeat.

If the people do not cooperate, then “the jackals” enter the scene, and get rid of the non-complying figures through violent means. If that fails too, there’s always war.

This is not a global conspiracy, but a modus operandi that has been initially used by the US and then by other countries, and effectively constitutes a new form of imperialism.

So far, so good. This, is honestly quite familiar to anyone who read a book or newspaper in the last 50 years, but the idea of reading a first person account is intriguing.

Sadly, the book does not hold up. It’s basically a collection of random stories which are so transparently fake that it’s incredible someone thought to write them down. Like, the guy gets recruited by the NSA be a spy. But the NSA is a code-breaking organization, it does not do that?

Then he meets this woman who explains him of the economic hit man concept Then she obviously tells him “if someone does not play by the rule <throat slash sign>“. Other than obvious corniness, I kinda think this gesture was not popular until much more recent times.

Or, the guy shows up after 9/11 in New York, and obviously meets an old muslim dude who gives him life lessons. He goes to Iran, and also meet people who give him life lessons and tell him how the West is killing their traditional Bedouin culture of leaving in the desert, “a true Persian would not allow that“. But Bedouins are like 1% of the population of Iran?

Anyway, you might say, sure, he’s embellished a story, but there will be some meat in it.

Nope, nothing. He spends an inordinate amount of time describing some situations were the US overturned a government, which you can trivially read on wikipedia, and that in all cases do not show the pattern of the countries being highly indebted, or not even match his own timeline (I.e. they predate the existence of IMF/WB). His first example, the one where he “sells his soul for the first time”, is Indonesia, which still has a debt/GDP ratio of 30-40% (compare: Italy has 130%, Germany 80%) and the poverty rate fell from >60% to 15% in the ’80s, after they started to take on debt (yes, correlation is not causation).

The even more embarrassing thing is that examples of the issue that he wants to talk about would be easy to find! He just doesn’t bother!

It’s a terrible book. But, if you never heard of any of this, it might be interesting, and the last part, basically a “what can I do“, is probably valuable. Caveat emptor.