Procedure All The Things! πŸ₯³

Blender 3.1 is out!, and I made a thing, and that makes me so happy. (πŸ‘β‰–β€Ώβ€Ώβ‰–)πŸ‘

The laundry list of enhancements and features is very long, but 2 are especially important to me right now:

  • support for Metal acceleration on M1 (I can finally make the fans on my new laptop go)
  • procedural geometry nodes

Now, if you read what I write every once in a while, you'll know that I'm a big fan of anything that automates and facilitates manual tasks. I'm a developer after all.

Back on the old blog, I used to rave about the superior procedural texture system in blender that mostly allowed me to get free of images and UV maps. Granted, I'm no artist, and I tend towards mechanical/naturalistic scenes where procedural textures can be used. It's just so great to set a few parameters and see a decent result without having to spend hours in a pixel editor. Plus, it works at any resolution. So, there's that.

Back when Blender got its revamp and started getting some attention again, the white whale on the forums and various conversations was "when will we be able to node all the things?". It's is a very hard problem to solve, and the blender community has been at it like maniacs.

And... geometry nodes are finally here. I can finally replace most of my particle systems with a nice, clean, geometry node.

On a lark, I decided to retake my huge island project, a re-imagining of the Island of Myst that used to take 5h/frame to render, because of the millions of leaves, blades of grass, and rocks that the particle system generated. It was very hard to work with because the RAM usage would explode and renders would fail sometimes. Without culling and boolean operations dealing with the field of view, the scene used in the vicinity of 24G, making it all but impossible to render on a GPU that I can afford.

After a little experimenting to get my feet wet, I managed to visually get roughly the same result on less than 2.2G of RAM. That freed me to add... more geometry and more complexity πŸ€“

And because of the M1 architecture, the ceiling of VRAM usage is very high anyways, so I let it rip and got even more geometry in.

There is somewhere between 2 and two and a half billion polygons that I know of. Probably more.

Here is the original I based my scene on:

From the Wikipedia page

The end result is this (warning -- 4K image):

Myst Library

It uses 3.7G of VRAM (😳), about an hour and a half to render on a laptop (πŸ€ͺ), it's not even as complex as I can make it go (πŸ€“), it's all geometry, no bump map tricks (🀩), and I could finally check that there were fans in my laptop (πŸ™ƒ)

I could do better on the render side, the complexity of the lighting means a lot of artifacts, and, of course, as I said before, I'm no artist, so some of the geometry is a bit iffy. Plus it's only 1024 samples, because I wanted to be fast-ish.

But Blender continues to impress, and who knows? Maybe they'll add a Do-What-I-Want-No-What-I-Type button in a future release that will magically enhance my skills.


[Rant?] Managing Frustrations Is More Important Than Managing Expectations

Every year, I see a plethora of books and articles affirming they can teach you how to manage your expectations - most of the time lowering them - because it's a source of unhappiness, and frustration.

In the current "mindfullness" boom, coupled with a pandemic that stresses everyone, it's not really a surprise that telling people to aim for attainable goals is popular. Why should a person add stress on top of stress by picking objectives they can't actually reach?

It irks me.

Now, of course no one should pursue truly impossible goals. But being told to "manage your expectations" puts squarely on your shoulders all the blame for being stressed, while failing to address the problem with your place in society. It reeks of "know your place" or "don't dream too big".

Most of the "expectations" aren't yours 🌍

We have customers, bosses, employees, colleagues, friends, and family who have expectations of us.

My current job is to make sure students that come into my care will leave it better prepared to work in the tech industry.

My expectations:

  • the students will trust me to know what's best for them, and (reluctantly, maybe) do what I suggest they do
  • the teachers working with me will trust me that I know what I'm doing
  • everyone involved will deal with the various inconveniences with good graces (the students will do their homework and be curious, and the teachers will be fair and uplifting)
  • I will have enough time in a day's work to deal with most emergencies

Everyone else's expectations:

  • the government, school staff, students (and their families) want me to design the classes in such a way that getting a job at the end is a guarantee
  • the school wants me to make sure the curriculum is attractive enough for prospects to sign up
  • the teachers want to have a decent environment, pay, and freedom to be flexible, so that they can impart their knowledge and experience to the next generation
  • the teachers want students prepared in advance to learn what they have to teach
  • the students want actionable knowledge - none of that philosophy and what-ifs - so that they can earn a living
  • the students want to have as much free time as possible, while being paid as much as possible
  • "the market" wants to be able to put ex-students to work as fast as possible, for a pay that's as low as possible
  • governmental rules want me to enforce regulations, such as attendance and other disciplinary actions
  • the students want me to bend the rules in their favor
  • "the market", and the students, and the school, want me to make sure that the curriculum in unmarred, and that only the "deserving" get their diploma
  • and
  • so
  • many
  • more

These are all high-level expectations, the nitty gritty is way more involved. And it's obvious that respecting all these is akin to squaring the circle.

So, "managing my expectations", in the way people have been explaining it to me over the last decades, would be to forego my expectations, or at least lower them enough, in order to make sure I can actually turn them into a reality. It says nothing about bucking against everyone else's expectations. I'm supposed to try and accomplish the goals that have been set for me by my superiors, and force people I have power over to do what they are supposed to, revising their expectations lower.

That definitely looks like a self-sustaining power structure to me, reinforced by a philosophy of "don't expect too much or you'll be sad". The higher up the chain, the more you can dream, because your dreams will become orders for others. "Manage your expectations" if you are not in a position of power.

Manage your frustrations 😀

You can't absolutely control others. My students will sometimes be "unable" to hand in homework. My teachers will sometimes be overwhelmed and forget to grade some papers. My hierarchy will sometimes forget that life outside of school exists for me too. My family will sometimes take affront at the time I devote to the pupils or the teachers.

It is frustrating, because a very large majority of people feel like they are already giving 110%, and my priorities aren't theirs.

An easy way out of that frustration is, indeed, to lower my expectations, and respect the letter of whatever law, rule, or guideline, I have to enforce. Passing the buck in terms of personal responsibility (I'm just "following orders"). I can also lower my expectations by leaving aside anything that would cost me extra energy, that isn't strictly mandated by someone in power.

And therein lies, for me, the crux of the semantics problem. By saying people should take upon themselves to "manage their expectations", even if your intention is pure and you are trying to protect their mental health, you are in essence telling them not to dream too big. It's a race to the bottom.

Collaboration doesn't work like that. Sure, personal goals rarely align perfectly, and everyone has goals outside of whatever we're working together on. But whenever humans are involved, compromise is the norm, and that means that everyone has to deal with a little bit of frustration.

Let's take a practical example: teaching a class about program design. It's one of these things that can be seen as a waste of time by a lot of people. Except, of course, by people who've learned the hard way that if a program isn't designed first, the future holds a metric ton of headaches.

  • the students don't have that experience, so they have no practical reason to spend hours learning something that goes contrary to what they know: a program either works or doesn't. Who cares if it's elegant?
  • "the market" wants them to be operational, which to them usually means fast, not spending hours seemingly doing nothing about writing code.
  • the school system isn't properly equipped for evaluating "grey area" skills. Since there is no "best" way to do something, how can anyone grade something like this?

The easy way out of this pickle is to remove that course entirely. The students are happy, "the market" is satisfied enough, the school system churns along. Β Lower my expectations, right? Sure, the next generation will make the same mistakes over and over again, but they will eventually learn, graduating to senior positions in the process.

And my frustration about seeing and sometimes using badly designed software, about seeing good developers burnt out by constantly running after technical debt, about people who should have no business making technical decisions forcing bad ones on people for expediency's sake, and about users having to work around the products they use, is ultimately irrelevant. Because everyone will friggin manage their expectations.

Oooooooor... I use my frustration, and use it constructively to educate people about all that. I teach them that they should definitely not lower their expectations but demand better, even if they might not get it. I try to teach them that a little bit of frustration can be the impetus towards a better world. You're unsatisfied? Do better.

The Karen Paradox 🀬

People will point out that this is exactly what the Karens of the world do: they demand better than what they get.

That is true enough. They strive for better, which is a good thing, if you ignore everything that has to do with a context. But I would argue it's because they cannot manage their frustrations. They put their want of not having any frustration whatsoever before any other consideration, especially the frustrations of others.

This is different from having unwarranted frustrations. Sometimes, a Karen forces us to see a problem we weren't aware of, even if the problem in question is dealing with Karens.

By the way, I find it hilarious that a first name is used as a label. I apologize wholeheartedly to good-natured Karens out there... It's not your fault, I know. But it's also not the first time a first name has gathered a reputation for malice. It'll sort itself out in the end, we love the "Good Karens" still.

Manage your frustrations πŸ˜“

And so we come full circle: yes, managing your frustration does involve managing your expectations. Being frustrated at not being an astronaut, or rich, or famous, or whatever we feel we deserve shouldn't be that big of a deal, and maybe in some instances, managing expectations are a good way to manage our frustration.

But it lacks ambition. Exploration, research, innovation, charity, support, everything that's good about the human species stems from looking at a situation, being frustrated by it, and trying something else.

Mind you, a lot of things that are bad about the human species, such as greed, oppression, and the like, also stems from frustration (see the Karen Paradox above), but that's humans for you. They are complicated, and as much as the say they'd like everything to fit in neat boxes with clear delineations, they'll do their damned best to blur the lines the first opportunity they get.

As a long time player of various role playing games (pen and paper too, yes, you irreverent youngins), I like to think of my frustrations as belonging to two very distinct categories: those that stack, and those that don't.

Frustrations that stack tend to amplify each other, being connected to one another, and are usually harder to "fix". Frustrations that don't stack contribute to the overall level of stress and dissatisfaction, but are independent, and the "fix" can be anything from super easy to super hard to impossible. Factor in the "what can I do about it" part, and there's something of a path towards a better tomorrow that doesn't involve quitting or blindly following directives. It's never as well delineated as that.

Let's take an example: I'm late for a class, because the subway is stuck. I know that it means my class will be shorter, and since a good portion of the students haven't spent the necessary time to understand fully the last one (or indeed hand their homework in), it will be even shorter because of all the time we'll spend rehashing the same things. That, in turn, will mean they won't be as well prepared as I hoped for the rest of their studies, or indeed their professional lives.

First frustration: I'm late. People around me behave in a way that make me cringe because they are frustrated. The whole situation is really, really, annoying. I'm not going to yell at the driver or the subway staff (even if they might be able to do a better job at handling the situation, I'm sure they have their own set of things to deal with that I'm unaware of, not being, you know, educated in the art of making trains run on time). I could tell the guy next to me that him yelling in his phone that he'll be late prevents me from doing the same. Should I? Maybe, if the call lasts for ever, or if in a stroke of bad luck he actually starts running the meeting by yelling into his phone. Will it solve the problem, or create a new one?

I want to make sure the tardiness won't impact the class too much. Should I send a message to the class asking them to start working without me? Without guidance, it could be a waste of time, either because they won't do it seriously, or they won't know how to do it properly. If I flex my power and tell them it's going to be graded to ensure compliance, is it getting me closer to my goal? Will they be better professionals, and/or will they think that sometimes, people in power dish out punishment because they are frustrated? What if they all do it diligently but fail? If I keep the grade in their record, it can be really unfair to them, and they won't trust me much after that. And if I don't, don't I show them that it was just a power flex, and they can safely ignore the next one?

This is not one frustration, but a conflation of two. One that stacks (the impact on my students) and one that doesn't (the fact the subway is late). Recognizing that some things are beyond my control and therefore that the frustration I feel towards those things have to be endured is a good thing, in my mind. Maybe next time, I'll have a bigger margin for transport, or a good book to pass the time, or noise-cancelling ear pieces. But that frustration will come and go, and I refuse to let it affect my decisions towards the rest.

Second frustration: I need to get my students more curious, more involved, more industrious about the topic so that if I am unavailable for 15 minutes, it doesn't matter that much. This has nothing to do with the subway being late.

I want them to want to research the topic. I am frustrated that they don't see the point. Is it their fault? Probably to some extent, so I need to coerce them a bit, because I know they won't have a glorious revelation with a ticker-tape parade, lights and fanfare, out of the blue. But it's also my responsibility. Why don't they trust me that this is important? Have I not given enough proofs of that? Were they unconvincing ones? Maybe it's because this class is among many many others, and everyone is vying for their attention? Maybe it's because I keep telling them it's important, but I'm not showing why often enough?

This is a frustration that stacks: it has a direct impact on many other tasks that I have to do, will have an effect on the extra time I set aside for preparing classes, preparing exams and grading them, will impact how the colleagues see my work, my relationship with other teachers and school staff.

This is a frustration that should drive me to do better. I should treasure it as an engine of change. And, sure, if I lower my expectations, it'll go away, just like the memory that I was late once because the subway was not moving. And maybe I'll be happier. Or at least less stressed.

We progress by being unhappy about our current situation and doing something about it. Not by shifting the responsibility onto someone else fully (as opposed to Karens), and definitely not by going all fatalistic and aiming only for what we're guaranteed of getting.

Frustration is a good thing (in moderation) πŸ€”

Look, we all know the rush of being validated, of having things go our way, of being right.

Some of us know that the pleasure of gratification is even better if we had to overcome something in order to get it. We're not talking sexual kinks here, although they are definitely a good indicator that this is a real thing.

There is a reason why so many people like brain teasers, word games, sports competitions, etc. There is a reason why the 3 acts are such a staple of stories in every culture. Without obstacles, where is the reward?

I tell the students that there are very few pleasures more satisfying than working on a bug for a few hours or days and suddenly finding a solution. You feel smart, tall, handsome and powerful, afterwards.

That satisfaction doesn't happen if the process is:
- realizing there is a problem
- looking the solution up
- applying the solution blindly
- end of the problem

I mean, a lot of life is like that, and that's ok, but I don't think it gives pleasure to people. It is frustration without a satisfactory ending. Sure, the job gets done, but machines will do that better than us, eventually.


[UPDATE] A Lil Bit Of Color

It's been a while. Two years ago feels like an eternity. I have been messing around with a lot of experiments in and around data, and swift, but nothing I felt particularly inclined to publish.

Pretty much my whole time was sucked up trying to take care of the students and helping the school staff not burning out too much.

I have lots of opinions, anecdotes, and the like, but I just don't feel like communicating on them just right now.

Instead, I decided to put some color back in my public life, including this blog.

And of course, as soon as I start hacking around interesting (and publishable) stuff, or have opinions I'll feel like sharing, I will start writing again.

In the meantime, COLORS! πŸŽ‰πŸ₯³πŸŽ‰


[Dev Diaries] ELIZA

Back in the olden days...

Before the (oh so annoying) chatbots, before conversational machine-learning, before all of that, there was... ELIZA.

It is a weird little part of computer history that nerds like me enjoy immensely, but that is fairly unknown from the public.

If I ask random people when they think chatting with a bot became a Thing, they tend to respond "the 90s" or later (usually roughly ten years after they were born, for weird psychological reasons).

But back in the 60s, the Turing Test was a big thing indeed. Of course, nowadays, we know that this test, as it was envisionned, isn't that difficult, but back then it was total fiction.

Enters Joseph Weizenbaum, working at the MIT in the mid 60s, who decided to simplify the problem of random conversation by using a jedi mind trick: the program would be a stern doctor, not trying to ingratiate itself to the user. We talk to that kind of terse and no nonsense people often enough that it could be reasonably assumed that it wouldn't faze a normal person.

It's not exactly amicable, but it was convincing enough at the time for people to project some personnality onto it. It became a real Frankenstein story: Weizenbaum was trying to show how stupid it was, and the concept behind man-machine conversations, but users kept talking to it, sometimes even confiding as they would to a doctor. And the more Weizenbaum tried to show that it was a useless piece of junk with the same amount of intelligence as your toaster, the more people became convinced this was going to revolutionize the psychiatry world.

Weizenbaum even felt compelled to write a book about the limitations of computing, and the capacity of the human brain to anthropomorphise the things it interacts with, as if to say that to most people, everything is partly human-like or has human-analogue intentions.

He is considered to be one of the fathers of artificial intelligence, despite his attempts at explaining to everyone that would listen that it was somewhat a contradiction in terms.

Design

ELIZA was written in SLIP, a language that worked as a subset or an extension or Fortran and later ALGOL, and was designed to facilitate the use of compounded lists (for instance (x1,x2,(y1,y2,y3),x3,x4)), which was something of a hard-ish thing to do back in the day.

By modern standards, the program itself is fairly simplistic:

  • the user types an input
  • the input is parsed for "keywords" that ELIZA knows about (eg I am, computer, I believe I, etc), which are ranked more or less arbitrarily
  • depending on that "keyphrase", a variety of options are available like I don't understand that or Do computers frighten you?

Where ELIZA goes further than a standard decision tree, is that it has access to references. It tries to take parts of the input and mix them with its answer, for example: I am X -> Why are you X?

It does that through something that would become regular expression groups, and then transforming certain words or expressions into their respective counterparts.

For instance, something like I am like my father would be matched to ("I am ", "like my father"), then the response would be ("Why are you X?", "like my father"), then transformed to ("Why are you X?", "like your father"), then finally assembled into Why are you like your father?

Individually, both these steps are simple decompositions and substitutions. Using sed and regular expressions, we would use something like

$ sed -n "s/I am \(.*\)/Why are you \1?/p"
I am like my father
Why are you like my father?
$ echo "I am like my father" | sed -n "s/I am \(.*\)/Why are you \1?/p" | sed -n "s/my/your/p"
Why are you like your father?

Of course, ELIZA has a long list of my/your, me/you, ..., transformations, and multiple possibilities for each keyword, which, with a dash of randomness, allows the program to respond differently if you say the same thing twice.

But all in all, that's it. ELIZA is a very very simple program, from which emerges a complex behavior that a lot of people back then found spookily humanoid.

Taking a detour through (gasp) JS

One of the available "modern" implementations of ELIZA is in Javascript, as are most things. Now, those who know me figure out fairly quickly that I have very little love for that language. But having a distaste for it doesn't mean I don't need to write code in it every now and again, and I had heard so much about the bafflement people feel when using regular expressions in JS that I had to try myself. After all, two birds, one stone, etc... Learn a feature of JS I do not know, and resurrect an old friend.

As I said before, regular expressions (or regexs, or regexps) are relatively easy to understand, but a lot of people find them difficult to write. I'll just give you a couple of simple examples to get in the mood:

[A-Za-z]+;[A-Za-z]+

This will match any text that has 2 words (whatever the case of the letters) separated by a semicolon. Note the differenciating between uppercase and lowercase.
Basically, it says that I want to find a series of letters on length at least 1 (+) followed by ; followed by another series of letters of length at least 1

.*ish

Point (.) is a special character that means "any character", and * means "0 or more", so here I want to find anything ending in "ish"

Now, when you do search and replace (is is the case with ELIZA) or at least search and extract, you might want to know what is in this .* or [A-Za-z]+. To do that you use groups:

(.*)ish

This will match the same strings of letters, but by putting it in parenthesiseseseseseseseseses (parenthesiiiiiiiiiiiii? damn. anyway), you instruct the program to remember it. It is then stored in variables with the very imaginative names of \1, \2, etc...

So in the above case, if I apply that regexp to "easyish", \1 will contain "easy"

Now, because you have all these special characters like point and parenthesis and Β whatnot, you need to differenciate when you need the actual "." and "any character". We escape those special characters with \.

([A-Za-z]+)\.([A-Za-z]+)

This will match any two words with upper and lower case letters joined by a dot (and not any character, as would be the case if I didn't use \), and remember them in \1 and \2

Of course, we have a lot of crazy special cases and special characters, so, yes, regexps can be really hard to build. For reference, the Internet found me a regexp that looks for email adresses:

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

Yea... Moving on.

Now, let's talk about Javascript's implementation of regular expressions. Spoiler alert, it's weird if you have used regexps in any other language than perl. That's right, JS uses the perl semantics.

In most languages, regular expressions are represented by strings. It is a tradeoff that means you can manipulate it like a string (get its length, replace portions of it, have it built out of string variables etc), but it makes escaping nighmareish:

"^\\s*\\*\\s*(\\S)"

Because \ escapes the character that follows, you need to escape the escaper to keep it around: if you want \. as part of your regexp, more often than not, you need to type "\\." in your code. It's quite a drag, but the upside is that they work like any other string.

Now, in JS (and perl), regexps are a totally different type. They are not between quotes, but between slashes (eg /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/). On one hand, you don't have to escape the slashes anymore and they more closely resemble the actual regexp, but on the other hand, they are harder to compose or build programmatically.

As I said, it's a different tradeoff, and to each their own.

Where it gets bonkers is how you use them. Because the class system is... what it is, and because there is no operator overload, you can't really get the syntactic elegance of perl, so it's kind of a bastard system where you might type something like

var myRe = /d(b+)d/;
var isOK = "cdbbdbsbz".match(); // not null because "dbbd" is in the string

match and matchAll aren't too bad, in the sense that they return the list of matching substrings (here, only one), or null, so it does have kind of a meaning.

The problem arises when you need to use the dreaded exec function in order to use the regexp groups, or when you use the g flag in your regexp.

The returned thing (I refuse to call it an object) is both an array and a hashmap/object at the same time.

In result[0] you have the matched substring (here it would be "dbbd"), and in result[X] you have the \X equivalents (here \1 would be "bb", so that's what you find in result[1]). So far so not too bad.

But this array also behaves like an object: result.index gives you the index of "the match" which is probably the first one.

Not to mention you use string.match(regex) and regex.exec(string)

const text = 'cdbbdbsbz';
const regex = /d(b+)d/g;
const found = regex.exec(text);

console.log(found);
console.log(found.index);
console.log(found["index"]);
Array ["dbbd", "bb"]
1
1

So, the result is a nullable array that sometimes work as an object. I'll let that sink in for a bit.

This is the end

Once I got the equivalence down pat, it was just a matter of copying the data and rewriting a few functions, and ELIZA was back, as a libray, so that I could use it in CLI tools, iOS apps, or MacOS apps.

When I'm done fixing the edge cases and tinkering with the ranking system, I might even publish it.

In the meantime, ELIZA and I are rekindling an old friendship on my phone!


[Dev Diaries] CredentialsToken 0.2.0

I needed to write a login mechanism for a Kitura project, and decided to dust off the old project and bring it into 2020.

Changes include:

  • Update to Swift 5.2
  • Update dependencies
  • Added a cross-check possibility between app and client tokens

Grab it on github