Thursday, November 15, 2018

touch tablet paint program ui thoughts

I do daydream about making an expanded version of my self-published comic on coping with mortality, something that captures the best of my thinking not just on death but on the best way to get through life. 

I continue to look for the best app to do that with, experimenting with various paint programs (over the year I've spent so much money on devices with touch sensitive screens, each time thinking "maybe THIS will be the one that lets my doodle skills blossom") Apple iPad's "Notes" program probably can't be it (if only because it doesn't deal with layers) but it really has some interesting UI decisions: coloring with the marker is more or less two-toned, paint once then start painting on the same spot to get a darker shade. And the eraser tool is kind of wild: it's like using the "Undo" button (that might erase a set of lines squiggles you made without lifting the stylus all at once) but instead of removing the last thing you did, it removes what ever you poke with the eraser tool. It's disconcerting at first, but kind of encourages a "well if you mess up you can do that whole thing over" approach.

I'm appropriately humble about my doodle skills, but looking at the sesame street characters I drew from memory during a meeting, I wonder if some of the lack of depth most of my stuff has comes from my preferences for using flat flood fill to color with... it's interesting to let go of a kind of "coloring perfectionism". 

Tuesday, November 13, 2018

grep / search for multiple terms across files in php

"Hey, what's the matter?" 
"I'm sad because you're going to die." 
"Yeah, that bugs me sometimes too. But not so much as you think... ...When you get as old as I am, you start to realize that you've told most of the good stuff you know to other people anyway." 
--Richard Feynman and Danny Hillis. 

After blogging for almost two decades my site is an increasingly important supplement to my memory - it's great to have an archive for the full text of half-remembered quotes and excerpts.

A long while back I wrote a simple "grep" in Perl to find stuff - it could only find one exact string match across all the files, but often that was enough, and unlike Google, results were in chronological order, which was often useful. And its sense of usefulness (albeit mostly just to me) has increased over the years, so I decided to make it a little smarter and able to search for multiple terms and sentence snippets.

The logic turned out to be slightly trickier than I bargained for - the logic I finally realized I wanted was, for each file, go through each query term. Then go through the lines in the file. If for any query term none of the lines match, bail on this file, otherwise remember which lines matched. If we get to the end of all the terms, every term has at least one match - so for all lines that matched any term, sort 'em (having already made sure they were dedup'd), escape the HTML, bold the matching terms, and then return the lines as an array.

Here's the code for that:
function getLinesMatchingQueryStringInFile($file,$query) {
    $linesInFile = file($file);
    #break up query, using CSV (split on spaces after collapsing whitespace)
    $query = preg_replace('/\s+/',' ',$query);
    $queryterms = str_getcsv(trim($query), ' ');

    $matchingLineNumbers = array();
    foreach ($queryterms as $queryterm) {
        $lineNumbersMatchingThisTerm = array();
        foreach ($linesInFile as $linenum => $line) {            
            if (preg_match("/$queryterm/i",$line)) {
                $lineNumbersMatchingThisTerm[] = $linenum;
        #if any query term doesn't match we bail!
        if (count($lineNumbersMatchingThisTerm) == 0) { 
            return array();    
        } else {
             foreach($lineNumbersMatchingThisTerm as $linenum) {
                if (! in_array($linenum,$matchingLineNumbers)) {   
                    $matchingLineNumbers[] = $linenum;
    $res = array();
    foreach ($matchingLineNumbers as $linenum) {
        $matchline = htmlspecialchars($linesInFile[$linenum]);
        foreach ($queryterms as $queryterm) {
            $matchline = preg_replace("/($queryterm)/i","<b>$1</b>",$matchline);
        $res[] = $matchline;
    return $res;
A slightly clever bit (i.e. slightly deeper in the StackedOverflow) was trimming the query expression, and then using str_getcsv(), which does a good job of breaking something like 
find "something good"
something good
which is what I'd want to search on.

Friday, November 9, 2018

grumble grumble

Trying to follow a piece of data get mangled in a relatively declarative-style code base is a pain.

(FOLLOWUP: More specifically, the code in question was implicitly manipulating a lot of data for a financial estimation calculator - there was the display format (and my task was internationalizing that), the internal format used to do the math, and then the format for editing (i.e. you might want to display a money value with a currency symbol and a thousand place separator, but you remove it when the user is editing that value) It was frustrating when the "to" and "from" functions used in the reducer were each called like 2 or 3 times for every field. The correct solution turned out to be doing a "typeof" in the "toNumber()" routine, and if the argument was a string call the locale-aware number parsing function, and if it was a number just returning the number.  Now I'm not the biggest fanboy either of declarative styles (I still think event-driven code be a bit more sane- or at least easy to figure out what's messing up when things go awry) or of strict typing in javascript, but this experience made me thing the two might go well together.)

Thursday, November 1, 2018

git-r-done ux

Once upon a time, the comments section on my regular blog made it a social place, with regular commentators, only about half of whom I knew IRL.

Social media has moved on, alas. And adding injury to insult, my homebrew comment system got invaded by dirty rotten link spammers. These guys are the biggest jerks in the world. I have about 4,000 days with comments on them (!) but I'd say at least 3/4 of those will turn out to be nothing but comment spam.

Even after eliminating the ability for people (and bots) to post links, they kept on coming, and I decided not to give up, rather than invest more deeply into a fix.

But, being nostalgic and wanting to shake my fist against the onslaught, I'm going back and eliminating the spam while preserving the conversations. So I built a tool to efficiently drive through each entry and with a click, determine where the good comments started and the bots began, showing the actual entry to the right.

If there's no good comments, I click "KILL ALL" and the thing is removed. Other wise, I click a link that says "truncate the comments section here". (In the screenshot you get the idea of my crude but functional system: the first line is a count of how many comments in the file (for efficient "See X Comments" labeling when building the blog entry page), then each comment is followed by special lines in brackets "[[]]", with key/values for their name, and the time they posted.

To improve the UI, I make use of the fact that most of the 'bot entries seem to be posted 3000 or so days (i.e. 8 years) after the original entry date - so anything over 1000 days old gets labeled in gray, with a red highlight on the day differential. Anything older than 10 days still gets a light gray treatment.

I could probably just write a script to discard any comment coming 1000 days or more after, but besides the fact it would throw out some good stuff and keep some bad stuff, I kind of like the nostalgia of the old conversations. Right now I'm up to 2003, as we move into Iraq.

UPDATE: write after I wrote this I realized I could it one better - 98% of the time I just click on either "KILL ALL" (where there's nothing) or at the transition point from "good" to "bad" comments. So I really git-r-done'd a javascript thing (long story short I wanted to keep things one pass in my PHP) to add a css style to the id of the "cut here" link and turn it bright yellow, and then another button that says "DO THE YELLOW" if I accept the verdict - that button is plunked at the top of the page so I don't have to find it with the mouse.

So, it's cruft-y as hell, but very efficient, and transparent: make it easy for the user (me) but "show your work" at all time, along with being clear what action you are going to do...

Dang, I wish "Git-R-Done" wasn't so Larry-the-Cable-Guy-ish!

minimalist css callout/tooltips has a pretty good, minimalist CSS callout. I got rid of the fixed height and shadows and just use the one direction I needed:

div.callout {
  width: 200px;
  display: none;

div.callout {
  background-color: #444;
  background-image: -moz-linear-gradient(top, #444, #444);
  position: absolute;
  top: 0.5em;
  left: 8em;
  color: #ccc;
  padding: 10px;
  border-radius: 3px;
  margin: 25px;
  min-height: 50px;
  border: 1px solid #333;
  z-index: 100;

.callout::before {
  content: "";
  width: 0px;
  height: 0px;
  border: 0.8em solid transparent;
  position: absolute;

.callout.bottom::before {
  left: 45%;
  top: -20px;
  border-bottom: 10px solid #444;

After whipping up a version of that (and having to have the onmouseover/onmouseout for both the triggering text and the callout itself it was pointed out to me that the bootstrap we use has a decent library for what it calls tooltips - it can be "onclick" ( the code is like 
) , it can be made to not escape  HTML,
and you can style it with CSS - selector is
 .tooltip .tooltip-inner
And also it's pretty good that it fallsback gracefully using the html5 default "title" tooltip behavior

Tuesday, October 30, 2018

BASIC and the joy of little improvisational programs

Daring Fireball just posted a link to a 2014 article, TIME Magazine's Fifty Years of BASIC, the Programming Language That Made Computers Personal. As Gruber puts it
For those of us of a certain age, a BASIC prompt was what you’d expect to see when you turned any computer on.
This article is the best I've read on the subject (marred slightly by the amount of ads on the page) In particular, I hadn't realized how important it was as computers moved from the batch process punchcard era to the expectations of real-time interaction we enjoy today - and of getting students to realize that programming was something that mere mortals could do.

That was in the 60s - in the 80s, BASIC was the bedrock of home computers - and most kids were given a chisel and some other basic tools so that if they were motivated, they could get the computer to do whatever they wanted.

The article briefly touches on BASIC's detractors. But as my friend Jeremy Penner (founder of everyone-can-and-should-make-games celebration site Glorious Trainwrecks ) mentioned to me, line numbers, while limiting in many ways, are a super intuitive way to get a kid making that first step of "computer programs tend to go step by tedious step". I think Dijkstra infamous complaint "It is practically impossible to teach good programming to students that have had a prior exposure to BASIC" is way out of line; understanding simple step by step flow does not preclude later learning of modularity and other more sophisticated topics.

As Harry McCracken writes:
BASIC was so approachable that you could toss off little improvisational programs with barely any effort at all. I probably wrote hundreds of them in my high school’s computer lab—games, utilities, practical jokes to play on my classmates. Most were meant to be disposable, and unless any of them show up on forgotten floppy disks at my parents’ house, almost all of them are long gone.
That hit home for me. In the 2000s, that's sometimes my style for stuff in Processing and P5.js (though I'm a bit of self-absorbed nerd so I archive "the good stuff" at Other people I know, like Anna Anthropy write books about writing your own games in Twine, Puzzlescript, and Scratch.

But it's still a long way from the "booting into BASIC" days - Mac/Windows/Phone environments are great program launchers, but don't have that ramp into "you type things and computer stuff happens!" Also, the gap between "real" programs and what an amateur can write is MUCH bigger than it was in 1980s - especially for games. "Casual" games are a welcome exception to that, but a beginner programmer usually isn't using a toolset for 3D stuff.

(An upcoming thing I'll be keeping an eye on is Dreams for PS4 - "a space where you go to play and experience the dreams of Media Molecule and our community. It’s also a space in which to create your own dreams, whether they’re games, art, films, music or anything in-between and beyond." That's the same folks who made LittleBigPlanet which had a pretty rich online maker community too, so it'll be neat to see what comes of it.)

Thursday, October 25, 2018

wa-tor and recreational computing

I've implemented a version of A.K. Dewdney's Wa-Tor from Scientific American's "Computer Recreations" column - it's a simplistic Cellular Automata-kind of thing, a simulation of sharks eating fish on a donut-shaped world (generally mapped onto a simple grid) You can see my version here. Kind of hypnotic!

I was partially inspired to get back to this by my UI Book Club where we just finished Edward Tufte's "Envisioning Information". It reminded me of a Windows 3.1 Version I messed with in college... in particular, it had a population graph that's always stuck with me, something like this:
I can't think of many graphs with a time element where time isn't just slapped on the X-axis - it's kind of cool how you can follow "time" as it makes its curvy path. It turns out this basically a "phase diagram" corresponding to Lotka-Volterra equations, the math that predicts predator-prey relations.

"Computer Recreations" was a big influence on me as a kid. The whole concept of recreational computing, programming for fun, is something that's been lost a bit. The home computers then were slow and with almost no memory and generally primitive, but you had full access to the machine. For kids in the era, even if you just used the computer to play games, you entered a BASIC command to load the game, and you probably learned a smattering of BASIC in school, and learned that you could make these computers follow your instructions and make original stuff.

Anyway, I wrote it in P5, and the code could serve as an example of having 2 P5 apps communicate a bit, even though the whole thing is a bit quick-and-dirty.