Wednesday, December 13, 2017

php - download in the browsers, not as a download

In making a band chart/pdf management system, I needed a method for streaming/download files.

PHP makes it pretty easy, but I had to bang around just a bit before I could figure out how to let it try and open stuff in a browser window (vs going to straight to the download folder)

The code ended up a s
if(securityCheck(getLoggedInUser(),$_BAND,false)){
if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: '.mime_content_type($file)); 
            #vs application/octet-stream or application/pdf
    header('Content-Disposition: inline; filename="'.basename($file).'"');
            #vs Content-Disposition: attachment
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
} else {
print "NO LUCK $FILENAME";
}
   exit;
} else {
print "UNAUTHORIZED";
exit;
}

The bits that were different from the original example I copy and pasted are in bold.

Also, I learned the power of urldecode() :-D

the state of javascript

The State of Javascript 2017 - Angular 1's high "would NOT use again" value is still validating for my prejudices :-D

Tuesday, December 12, 2017

what'd i say? what'd i say? on facebook

I've posted alot about facebook here, including talking about the UI/UX details they get right (that post was from before they added various reaction types instead of the ubiquitous like ... also before the full depth of the echo chamber effect and manipulation by outside parties was known...)

One small thing I've noticed is how if I make a post and then go away from the site, there's a small window of time where if I bounce back to Facebook, my own post is the first thing I see. Whether that's because people like the reassurance of "yes I really just posted that and it went through" or are prone to make comments or edits, it's a terrific little UX detail.

Thursday, December 7, 2017

freemarker boolean weirdness

Freemarker Madness - my coworker helped me learn that
<#if ((allYearsForTrimName!false) && (!canShow("f:listings.seoLinksVariantContext")))>`
does about what you'd expect (in terms of not executing the block if that canShow routine returns true) but
<#if (allYearsForTrimName!false && (!canShow("f:listings.seoLinksVariantContext")))>
(without the safety paren around allYearsForTrimName) always evaluates as true and executes the block.

(I also got reminded myself that while ftl functions can't really print to the page, you can assign stuff to a global-ish variable and print it after ... really, log/printf based debugging will always be a crucical tool in testing your assumptions, even when in a system that has a rich step through debugger.)

So the coworker mentioned freemarket documentation warns about that precedence glitch... but man, that's an annoying one! You really don't want your language messing up boolean operations...


Wednesday, December 6, 2017

the joy of text and todo

In the late 90s there was an online comedy series called "Computer Stew" (Ahead of its time - way before people were putting series on Youtube, or even before there was Youtube)

My favorite episode was a rap tribute to Notepad.exe- but it's the line from the introduction with John Hargraves and Jay on Speakerphone that sticks with me:
"Well Jay, it's getting to be that time of year when everyone is giving out their awards for best software..."
"That's right! Best office suite, best paint program! Best online game!"
"And you know which program would win hands-down in my book..."
"Unfortunately I do sir."
"It's Notepad, that little text editor that comes with Window? I love that thing, man!"
"I know you do. I can't understand it. I think you're insane. Folks, John manages the entire show with little todo-lists inside of NOTEPAD!"
"I love Notepad! It's small, it never crashes... they never add any features to it... in fact I think I feel a song coming on..."

My current favorite equivalent of Notepad.exe is Simplenote - it is cloud based but beautifully minimalist, I run the native app on iOS and MacOS (and can get to a webpage with all my info when on someone else's computer.) I love how it makes the first line of text the defacto title (a trick PalmPilots used) and how it never tries to duplicate the font and color of stuff pasted into it (those are two things that its competitor Evernote gets wrong - plus Simplenote never begs me to upgrade.) Also I periodically get Simplenote to let me download a zipfile, my complete archive that I can backup safely, on my own terms.

There's one limitation though - Simplenote's collection is a list, usually ordered by "last modified" (Though it allows you to "pin" notes to the top - I reserve this for a single "scratch" note that I use to transfer text between my laptop and my phone, great when I want to be wordy in a chat program that I don't have for Mac) But going back to Computer Stew, the line about "little todo-lists", plural, suggests Hargrave may have used Notepad in that style where you have multiple windows of the program running, each always open to its todo list, each nestled on its own certain part of the screen, allowing "muscle memory" to kick and in help you keep track of which list is which.

(Of course now "markdown" brings new options for documents that make sense as text or run through to something with a richer layout palette)

That use of Notepad is a digital version of "Post-It notes stuck 'round the cubicle", and in fact Macs come with a "Stickies" app that has a more skeuomorphic view of the same thing. But virtual-stickies-on-PC-screen aren't portable, so these kind of Todo lists have always been secondary to what I keep in a dedicated checklist app - on PalmPilots back in the day, and now on iPhone for the past decade. Checklists are great (epecially since I can set up daily or weekly or monthly recurring reminders) but they are kind of flat, missing the "muscle memory" of a 2D space.

Padlet is a web-based system that lets you do something like the stickies but in a multiple-machine way, by treating the browser as the overall surface area. The program's focus is collaboration, however, so lacks Todo features such as dated and recurring Todos. And while that view is great on a big screen, it doesn't work as well condensed onto a handheld device.

Once upon a time I grabbed to domain name "todo2d.com" as a placeholder for an app that would combine Padlet's sense of a 2D space with fundamental Todo features. Never got around to it, especially since the audience for it is a bit niche. Currently I use Appigo Todo on my phone, which is pretty solid, but I'd love to find a Todo App that allowed multiple list but with an option of viewing all the contents of all lists at once. (For example, I'd love a separate list for stuff where I'm waiting for someone else, or that needs to be done at home or at a specific store...

gesture interfaces and the tao of programming

Rant at work: "@##!@# Somehow I used some magic gesture on my touchpad, and now Slack is zoomed in - but its not the normal zoom I can adjust with cmd-+ and cmd-- and cmd-0 ; instead it's just decided that slack should be in a magic window that I can pan back and forth with two finger swiping, but I have no idea of how to make everything fit" (restarting Slack seemed to fix it though it felt like I had to do so twice.)

Gestures where an errant side of a finger creates radical behaviors violates this part of Tao of Programming
A program should follow the "Law of Least Astonishment". What is this law? It is simply that the program should always respond to the user in the way that astonishes him least.
BTW, the Tao of Programming is brilliant - it's weirdly authentic, like I've seen other things that parody the form of the Tao Te Ching but they generally don't also say smart things about their subject matter....

Tuesday, November 28, 2017

paper airplane as "send"

Can I just say, I love the "paper airplane" arrow chevron that means send in a few mobile apps? It's so cute, and still works even if you don't recognize it, since it still carries a sense of motion / go / send.

Saturday, November 18, 2017

a hack to avoid iOS music app's odd decision to play the first thing that comes to mind...

I try to be forgiving of UI/UX decisions that seem foolish to me, understanding that sometimes there are design constraints I might not be aware of that are driving the show.

One longstanding iOS annoyance/oddity is this: when a podcast or audiobook ends, control tends to revert back to the music app, which makes sense, but then the music app starts playing songs from its library, starting at the top, alphabetically.

I suppose that's better than playing from all songs on shuffle, since at least I got to recognize that the Jackson's Five "A.B.C." meant it was time to switch gears, but for me it's worse than say, picking up where I left off, playlist-wise. Or better yet - why play anything? Is silence so awful? Would people assume the chain from device to speaker has somehow busted if there's nothing but quiet?

So, a small hack - moviesoundclips.net has a page of clips from Aliens, I took "That's it, man. Game over, man, game over!", padded it to be that plus four minutes of silence, called it "a a a - game over man" and then made an mp3 of the result. A little playlist hackery to make sure it had a spot on my phone and I was set - now when podcasts ends I should hear that, rather than the Jackson 5 (don't get be wrong, it's a great song, but kind of loud...)

Tuesday, November 14, 2017

wrapping text on a curve path in processing

I made a Processing app to help generate this tuba bell cover:



Slightly hackier than usual (I was watching football and hanging out with my Aunt), I used Processing vs p5.js (like I did for my Halloween skull bell cover) because of some fumbling getting p5 to load the font I needed. (Gill Sans Ultra Bold)

Source and supporting files here.

My code started from this Processing forums post but improves it by having the top go around clockwise and the bottom counter clockwise, rather than just do a full 360 around a circle and making people strain their neck to read it. Then there was a lot of fiddling by hand to get the circle sizes to look right and the words to be in the right place.

A better version would take the actual letter width into account - this one is implicitly acting as if it were a monospace font, but I just wanted to get through it.

Thursday, November 9, 2017

mockupulator: simple rectangle drag and drop in p5.js

So random p5.js thing / tool that has a small chance of being useful for someone else: I was wanting to do simple but parsnickety layout mockups, but Acorn (my default image maniuplator) was being weird and I don't have Sketch (or much Sketch mojo) so I multitasked during the UI talk to make https://kirkdev.alienbill.com/2017/mockupulator/ - it's based on memories of an old "magnetic poetry" java applet I saw, you can just drag and drop the texty bits in the middle to where you want them.

Since the ENTIRE app is just the source code of that page (plus p5.js and the images I slice and dice) it would be easy to apply it to your own sliced up mockup.

Future versions I might never get to would make it save/restore state of the blocks and maybe make up blocks based on text rather than pre-existing image slices.

To quote Douglas Adams:
I have a well-deserved reputation for being something of a gadget freak, and am rarely happier than when spending an entire day programming my computer to perform automatically a task that would otherwise take me a good ten seconds to do by hand.
Ok, more like 50 minutes to save 10 minutes, but still!

Monday, November 6, 2017

"ExtJS was a mistake. One we, as a society, may never recover from."

When I worked at Pearson's startup Alleyoop around 2010 or so, we had an incredibly bright intern named Slater, currently CTO of his own machine learning startup.

On FB he posted
ExtJS was a mistake. One we, as a society, may never recover from.

Our dialog proceeded as follows

Kirk:
Oh my goodness. I thought you would be hipper and getting into the game after ExtJS was recognized as a mistake!
It's funny, I talked with this one engineer I respect but never should have been making UI architectural decision - In 2008 he put us on "Wicket"... all this client-y looking code is in Java, and you have to carefully keep synchronized these divs in the template and their corresponding nested Java objects... blargh)
In 2015 I was talking to him about his shoehorning us into Wicket, and what he, as a primarily serverside guy, would like in a UI. It turns out mostly he wanted to not have to learn HTML5 and especially CSS. "I want to be able to just ask for a button - programatically - and it gives me a button."
I realized ExtJS was probably an extension of this kind of thinking.
It was hard to learn and understand (rather opaque!) and also hard to debug in the browser - all these little widgets with absolute positioning and then given exact pixel coordinates... I'm sure they were doing some cool stuff early in a cross-browser way but man.
The hoops some engineers go through - the extravagant toolkist they then have to learn - to avoid learning some very basic stuff...

Slater:
In a bizarre twist of fate, I recently picked up react + redux (not that I know what I'm doing on the frontend), and then saw an ExtJS stack. Suffice it to say I was horrified, but I think you're spot on about the logic.
I get not wanting to learn a new toolset (one could argue that a lot of cases where node gets extended beyond its sweet spots is another flavor of this same thinking), but anyone should be able to recognize when a framework is pushing them toward unmaintainable code.

Kirk:
A lot comes down to if developers prefer to understand things bottom up / via reductionism (in which case they value very transparent tools - even if they have to write a lot of the grunt work code themselves - the code base might get gnarly and complex but at least it's complexity specific to the application at hand) or top down / holism (in which case they might prefer a richer toolset that makes it easier to write in broad strokes - if the toolset is harmonious with the problem that's great, but chances are the toolset solves MANY people's problems, not just yours, so if you have to track down a mysterious 'whyd this go wrong?' it can be brutal)
Besides the holism/reductionism split, there's also nouns vs verbs; devs like me prefer verbs - I want to describe what I want done, in a more or less procedural way-- whereas noun thinkers want to make something that knows how to do the stuff. So here I like react, where the nouns (the JSX bits embedded in code) live sprinkled among the verbs of code, and you can put in a very relevant breakpoint, or inspect the state. Vs ExtJS, where you specify the nouns and it tries to write the verbs to get you there, and god help if you need to track down how the nouns got to the state they did.
When it comes to toolkits, my heart lies with vanilla-js or DOM manipulators like jQuery - I cut my teeth on caveman CGI, where the DOM was a very static thing that came back in one fell swoop from the server. When I added jQuery into the mix, the verbs I could do in the client multiplied, but the DOM was still that static noun thing, changing only at certain points which were more or less easy to track. Over the years I've felt validated that this is a pretty strong paradigm, as I've seen toolkits come and go, but React has come closest to feeling what might be the actual future, and I don't want to jeopardize my career by sounding like a cranky old stuck in the past dude.

Slater:
Kirk, also I agree with this a lot. Personally I don't feel the noun/verb distinction super clearly, but that's probably because I switch between functional and OO paradigms a lot. I think especially for people coming from a noun-centric (read: Java) environment, learning the thought process behind a generally more verb-centric (read: javascript) environment can be very tough.
Additionally, I'm super, super reductionist. I like tools, and I love standing on the shoulders of giants, but I tread very cautiously when it comes to adopting a new framework, and it's very important to me to understand exactly where the limits of the tool are. I really enjoy APIs for this reason, and I think there are a lot of heavy frameworks that go the wrong way on this (for me at least) by enforcing large amounts of state, and making it unclear how you would extend the code.
I think jQuery is a really simple and straightforward way to built a project. I think that it's quick to pick up, fast to prototype with and for small projects there's nothing wrong with it. My gap comes from the perspective of maintainability. There are a lot of code smell niceties in something like python, generally focusing around clean code abstractions, decoupling data from logic, etc... that can be really hard to get right in plain jQuery. Even something like splitting code up into multiple files and using functions across them can get surprisingly gross pretty quickly just because of how the namespaces are set up.
I think that's the biggest advantage of React (I'll say Angular is pretty damn close to React, and from a macro-level they're almost interchangeable. Angular just feels like a bigger, clunkier version of React to me). Very clear separation of concerns. Clear lines of responsibility, and built for re-usability.

Kirk:
Enjoying this dialog Slater.
The way you used Java/Javascript as your example for noun v verb pinged something in me: I know the shared "Java" in the name is coincidental-ish but there's the "script" part - and that being verb-centric - "I want the computer to do this". It made me think of a defense of PHP I reread recently - Taking PHP Seriously - besides talking about how the odd dichotomy where the language is much reviled yet so many big league projects got at least their start in it - and in looking for some answers, mentioning that the script-ish way it gives you a "from-scratch" clean envioronment for each web invocation - that's actually tremendously powerful.
I can't always separate my long-standing biases (and roots doing personal projects where I was the only developer, though some of those codebases have lasted me decades, literally) from my "graybeard" experience, but I feel like I haven't seen much many systems that were clearly easier to understand and bring more people on later via leveraging higher level things. Whatever advantages were gained in using boilerplate were more than eaten away by a combination of new developers having less experience with the platform and generally being MUCH harder to debug from a bottom-up way. (i.e. completely opaque stack traces etc)
For namespaces... I dunno. Just throw everything into window.MyProjectName = {} and be done with it ;-D
The fact Angular and React feel so similar to you indicates that we view things very differently (admittedly I've done more hacking in Angular and only toy things in React so far). Elio who is posting here loves Angular, I hate it - who thought "client-JSP" would be a good idea? That is to say, "we love writing tags so much, we're going to let you make your whole View in nothing but tags - never mind how much syntax you have to learn in both the tagspace AND the plumbing that lets it all look like html tags. But more to the heart of our conversation, for me tags are nouns, the fairly static nouns of the DOM, so trying to make them all verb-y with loops and conditionals, and so it's blend of "this is a tag for the browser to render, this is a tag for the view's logic" feels strange to me. By putting the noun tags in the verb logic, React does something a little similar at a high level, but at least the logic and the display are in distinct languages (js vs jsx)
Heh, reminds me of How it feels to learn JavaScript in 2016 . Probably a warning sign that I still think more like a prototype cowboy is how much I looove just writing an index.html, a style.css, and app.js (and then I sort of love that "ok so put it all in one document anyway" paradigm ;-)

Anyway, very smart guy, one to watch out for.

Wednesday, November 1, 2017

iphone x is gestures all the way down

Slate: The iPhone X Takes Hand Gestures Too Far

I've never been a fan of gesture interfaces, and life with an iPhone X requires a whole new slew of them. (Conversely, I've always been a big fan of the home button; an easy to access "lets take it from the top" escape hatch can be enormously centering, like how when I click on a website's name in their header on any page I go to the site homepage.)

That's one of problems with the designer's dream of being such world-beater designers they they can stop having to actually, you know, design- having achieved the zen of "a piece of featureless glass"... the phone then just consists of an OS and apps - but having to designate certain finger moves as "ok, now you're communicating with the OS" makes a less known reliable channel, and one prone to accidental invocations, and takes away from the language of gestures that apps are allowed to use.

Thursday, October 26, 2017

moment of duh: search across ALL javascript in chrome dev tools

I was a little nonplussed at not seeing a widget (or having my normal keyboard shortcuts seem to work) for search ALL the scripts for a bit of javascript... but if you click on the vertical ... box under developer tools, there's a "Search all files".

Wednesday, October 25, 2017

clever UI for tight quarters and fat fingers

One of the few paper puzzle games I like goes by several different names - Nonograms, Picross (Nintendo calls it that in its digital versions), Paint-By-Number... actually the Wikipedia Page lists about 30 names for it- I feel like the branding is one of the reasons why it hasn't reached the popularity of, say, Sudoku - for my money, uncovering a small pixelated picture is immensely more satisfying than making yet another grid of numbers.

If you don't know, Picross gives you an empty grid, and then numbers for the rows and columns - so if a grid is 10 squares wide, and to the side of that row it says "10" you know the whole row is filled in - or if says "5 4" you know it's 5 squares and then 4 squares,  and since there must be a blank between, you know the pattern exactly, since 5 + (1 blank) + 4 = 10. Usually there's some ambiguity, like "1 3 1" and you have to cross correlate with the columns to figure out what's going on exactly

I found a decent version for iOS called "Picture Cross" - it's free, but for a any purchase (as cheap as 99 cents) the annoying advertisements go away. By default a simple puzzle in it looks something like this:

The UI is pretty easy, the center "Fill In" and "Blank X" buttons are modals - the checkbox shows you which mode it's in - click any empty square, or drag across squares, and it gets filled in with marks or blanks.

That's tricky once you start getting more squares (15x15 or more) or if you have a small phone, so they include an "Alternate" control scheme that takes a second to figure out but then works really well. The mode adds a "pin" button and a cursor:


The nice thing is, the cursor moves from its location no matter where on the screen you swipe, so you can see exactly what square you're talking about it without your finger blocking it. So from there you can go ahead and click the Mark or X button and it toggles the state of the box under the cursor.

In this mode, the pin button is what's modal. Click it, drag-swipe, and an entire region is selected, with the first square being where the cursor started: (in this case, according to the rules of Picross, we know that all 10 squares along the bottom are due for being marked...)


Then you can click the "Mark" button, and all the square are set.

So when you have a base like that in Picross, the next step is easy, since we've anchored all the bottom numbers along the top - the 1 and1 is set, the 4 and the 6 we know how they'll go.. so I'll unpin the selection, and go to the column of the 4..., pin and drag...

Mark as filled...



Here's a detail that's cool - I know there's nothing but the 4 in that column, so I can should the rest with X blanks. I just drag up to the top of the column, and hit the X button...

The clever part of this UI is that it doesn't undo what I've already marked. I feel like a more naive UI would just do "whatever is selected, change its state" but Picross encourages being conservative in how you mark things, so you don't want them casually unmarked - that would be super confusing.



That "don't change state directly from marked to X" rule applies even if you're checking squares one by one, for similar reasons.


techie cheatsheets galore!

https://devhints.io/ - TL;DR for developer documentation
"A ridiculous collection of web development cheatsheets"

Monday, October 23, 2017

sublime - autosave when you change apps

The new hotness standard brought by IntelliJ seems to be autosave, cmd-s is old and busted.  For a while I thought this was black magic but I think sometimes it's as simple as a "save when you lose focus".

I still use sublime for other work, and among some other tips this page tells me I can just add
"save_on_focus_lost": true
to my preferences>settings (currently set to
{
"auto_match_enabled": false,
"color_scheme": "Packages/Color Scheme - Default/Solarized (Light).tmTheme",
"font_size": 15,
"auto_close_tags": false,
"save_on_focus_lost": true
}
for what it's worth.

From a UX standpoint, autosave is kind of an paradigm shift, but in an age of really good cmd-z undo, it's not as problematic as my old self would have thought.

Friday, October 20, 2017

Thursday, October 19, 2017

more quick and dirty php: finding matching tags

Just here for my future reference - did another "PHP as command line scripting tool to recursively go over directories", this one to get a rough idea of, in our Freemarket Template codebase, how many
<#macro fooBar blah blah>
macro definitions were orphans, and never called with a
<@foobar blah blah >
tag. (Freemarker is hella flexible in terms of how you build a macro name to call, though, so this is far from bullet proof...)

<?
$directory = "/Users/kisrael/cargurus/cg-main/cargurus-site-static/templates/";

$macroDefLocations = array();
$macroCallLocations = array();

#checkfile("inventorylisting/ocrFilterMacros.ftl");

$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory));
while($it->valid()) {
    $pathname = $it->getSubPathName();
    if (endsWith($pathname, ".ftl")) {
    checkfile($pathname);
    }
    $it->next();
}

function checkfile($pathname){
global $macroDefLocations, $macroCallLocations;
    lookForMatches($pathname,$macroDefLocations,"/\<\#macro.*?\>/s","/\<\#macro\s(\w*)\W/s");
    lookForMatches($pathname,$macroCallLocations,"/\<\@.*?\>/s","/\<\@(\w*)\W/s");
}

foreach($macroDefLocations as $definedMacro => $usages){
if(! array_key_exists($definedMacro, $macroCallLocations)){
$file = array_keys($macroDefLocations[$definedMacro])[0];
print "[".$definedMacro."]\t".$file."\n";
$orphanedMacrosInFile[$file]++;
$orphan++;
} else {
$calledMacrosInFile[$file]++;
$wellcalled++;
}
}
#print "$orphan orphans $wellcalled called\n";
#print "CALLED:\n";
#print_r($calledMacrosInFile);
#print "ORPHANED:\n";
#print_r($orphanedMacrosInFile);

foreach($orphanedMacrosInFile as $file => $countOrphans){
$countCalled = 0;
if(array_key_exists($file, $calledMacrosInFile)){
$countCalled = $calledMacrosInFile[$file];


$percentOrphans[$file] = (100.0 * ($countOrphans) / ($countCalled +$countOrphans ));
$orphanDesc[$file] = "$countOrphans orphans / ".($countCalled +$countOrphans)." defs";

}
arsort($percentOrphans);

$keys = array_keys($percentOrphans);


foreach($keys as $file){
print round($percentOrphans[$file],3)."\t".$orphanDesc[$file]."\t".$file."\n";;
}


function lookForMatches($pathname,&$results,$regexFind,$regexExtract){
global $directory;
$content = file_get_contents($directory.$pathname);
preg_match_all($regexFind,$content,$matches);
foreach ($matches[0] as $key => $tag){
preg_match($regexExtract,$tag,$finds);
$macro = $finds[1];
#print "vvv\n$tag\n^^^\n";
if (! array_key_exists($macro,$results)){
$results[$macro] = array();

if (! array_key_exists($pathname,$results[$macro])){
$results[$macro][$pathname] = 0;
}
$results[$macro][$pathname]++;
}
}

function endsWith($haystack, $needle) {
    return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false);
}
?>

Tuesday, October 10, 2017

The one true Javascript exception handler:
try {
  something
} catch(e) {
  window.location.href = "http://stackoverflow.com/search?q=[js] +" e.message;
}
(via)

Monday, October 2, 2017

what perl taught me (in the early-mid-90s)

Perl was the first language I learned after the "C" that was taught in my Intro to Computer Science class (so probably my fourth language overall, after BASIC and Logo growing up.)

Compared to C of that era, it was like manna from heaven. Here's what it gave me that C lacked:

  • Maps, or as Perl called them, Associative Arrays. Key/Value pairs are such an ENORMOUSLY powerful concept, and this was my first exposure to them.
  • Regular Expressions - being able to match strings is also very powerful and fundamental
  • Strings as first class entities - compared to C saying "you can make a string as an array of strings ending with a \0 character", this was great. In this way too, C was oddly inferior to the BASICs I grew up with.
  • Duck-Typing. I'm not as sold on the importance of duck-typing as I used to be, but I liked it. I especially like Perl's habit of quiet context-based assumptions... assuming false-y or null things are zero if you're trying to do math, compared to Javascripts tendency to panic with "NaN" is more robust and less error-prone than some purists probably realize.
  • Not having to micromanage memory. Man, was C annoying in this regard; having to carefully de-allocate every hunk of memory explicitly was a real pain. (In retrospect, Perl may have gotten away with this more because of its "script" feeling... in general things that do some work than quit can be more forgiving than long-running processes...
Such a breath of fresh air... and then when I learned I could rent cheap webspace that would let me run Perl and that CGI mapped fairly wonderfully to that Key/Value concept... the sky was the limit. I could do nearly anything the web could do.

I was shocked a decade later when a coworker pointed out that most of that stuff I loved about Perl was actually from its history as a glue language, wrapping C(!)-based Unix system calls.  That stunned me... I knew the wonky syntax came from Perl's history as a bit of a mongrel, but compared to other stuff (especially early PHP) it always felt very professional, you hardly ever saw the skeleton, and there wasn't much in it that was obviously for the convenience of the language implementer rather than the programmer. And all these new tricks felt like the very opposite of C...

These days, my Perl is decidedly rusty. PHP eventually matured and having all the stuff for webtasks baked into the language rather than the ugliness of CPAN module compiling was great. Also I'm worried I should have been learning Python, rather than blowing it off because the given task was easier in more familiar Perl. And I never did get my head wrapped around Perl's flavor of Object Oriented thinking. Still, I'll always be grateful to it for opening my eyes to new ways of thinking about programming, which is what the worthy languages and frameworks do.



quick jquery check for repeated / duplicate ids in DOM

Coworker suggested this console-code proof that ids were being duplicated:
  $('[id]').each(function(){
var ids = $('[id="'+this.id+'"]');
if(ids.length>1 && ids[0]==this)
console.warn('Multiple IDs #'+this.id);
});

If I was less lazy I'd cook up the non-jQuery version.

Tuesday, September 26, 2017

p5 editor to programmatically make a downloadable image in the browser

QUICK HACK: I have a lot of decent art programs for my iPad, but it seems like like such programs no longer come with tools for making simple shapes, like circles and squares. That made my inner child a little sad! Paint programs used to be fun, you know? Like just tooling around throwing shapes and patterns on the screen...

It's tough enough to find programs with flood fill, actually.... it seems like almost every art program is either imitating "real" art tools, aimed at photo retouching, or tries to get you to think in their weird interface for vectors.

Anyway, I wanted a colored circle as a base for a Jack-O-Lantern tuba cover I'm making, and the easiest way was to go to the online p5 editor and enter the following:

function setup() { 
  createCanvas(3000, 3000);
noSmooth();


function draw() { 
  background(255);
noStroke();
fill(255,140,0);
ellipse(1500,1500,2500,2500);
saveCanvas("art.png");
noLoop();
}

That actually generates a file "art.png" which the browser will offer to download.
I then used Dropbox to transfer it to my iPad.

UPDATE:  Did a bit more work...

So, I'm making up designs for tuba covers (as printed by the fine folks at http://stretchablecovers.net/) Before I mentioned the first step for a Jack-O-Lantern (drawn in by hand)

But a few years ago I had a DIY craft project (felt crudely stapled onto the blank side of a cover) skull for my tuba:


I lost it in my recent move, and decided I'd get it printed up, and that I'd use another p5.js program to do it. (I liked the idea of using shapes rather than being quite hand drawn).

Net, net, you can see and play with the p5.js program here. The moderately clever bit is using a technique to let me finesse the placement of a piece via "map()"ing the X and Y mouse position to appropriate values, and then building a string for the corresponding ellipse() or line() command. I then both print the screen and run javascript's "eval()" on it. Once I get the fragement where I like it, I copy and paste the printed version of the statement and place it into the code, so it's kind of baked into the place and then I repeat the technique for the next fragment.


Oh, also for funsies check out my old Carve Your Own Jack-O-Lantern Processing Program... very similar in spirit to all this.

For reference (since I guess I shouldn't an  account on a "alpha version" editor as a code repository) here is the code... it's not (quite) as hackish as it looks.

var BASE;
var s;
function setup() { 
  BASE = 30;// random(38,58);
  createCanvas(BASE*10, BASE*10);
strokeCap(SQUARE);


function draw() { 
  //BASE += random(-.1,.1);
  background(200);
noStroke();
translate(width/2,height/2);
fill(255);
ellipse(0,0,BASE*8,BASE*8);
fill(0);
push();
  var f1 = map(mouseX,0,width, -5,5).toFixed(3);;
  var f2 = map(mouseY,0,height, -5,5).toFixed(3);
  var s;
//var s = "bigEye("+f1+","+f2+");";
  s = "bigEye(1.835,-1.239);";
  eval(s);
  s = "nose(-1.867,0.824)";
  eval(s);
  
  //s = "smallEye("+f1+","+f2+")";
  s = "smallEye(-2.037,-0.947)";
  eval(s);
  
  s = "mouth()";
  eval(s);
  
  s = "crack("+f1+","+(f2)+");"
  eval(s);


}

function mousePressed(){
  noLoop(); 
}

function crack(a,b){
    strokeWeight(BASE/5);
  stroke(0);
  noFill();
  push();
 // print (a+":"+b);
  translate(BASE*.137,BASE*.44);
beginShape();
  push();
 vertex(BASE*-3.392,BASE*-4.471);
vertex(BASE*-1.704,BASE*-3.673);
vertex(BASE*-1.367,BASE*-3.895);
vertex(BASE*-1.316,BASE*-3.14);
vertex(BASE*-0.497,BASE*-3.36);
  vertex(BASE*0.084,BASE*-2.65);
//vertex(BASE*-0.894,BASE*-2.657);
vertex(BASE*-0.497,BASE*-3.36);
  vertex(BASE*0.143,BASE*-3.791);

  s = "vertex(BASE*"+a+",BASE*"+b+");";
 // eval(s);
 // print(s);
  endShape();
  pop();
  
  
    noLoop(); 
 saveCanvas("skull.png");

}


function mouth(){
  strokeWeight(BASE/2.8);
  stroke(0);
  line(-BASE*4,BASE*2,BASE*4,BASE*2);
  
  line(0,BASE*1.35,0,BASE*2.65);
  line(-BASE,BASE*1.45,-BASE,BASE*2.55);
  line(-2*BASE,BASE*1.4,-2*BASE,BASE*2.55);
  line(BASE,BASE*1.45,BASE,BASE*2.65);
  line(2*BASE,BASE*1.45,2*BASE,BASE*2.55);
}



function nose(a,b){
  push();
  push();
  rotate(a);
  ellipse(0,BASE/4,BASE*2,BASE);
  pop();
  push();
  rotate(-a);
  ellipse(0,+BASE/4,BASE*2,BASE);
  pop();
}

function bigEye(f1,f2){
  var g = 2.5;
  push();
  translate(f1* BASE,f2*BASE);
rotate(0.1);
  ellipse(0,0,BASE*g,BASE*g*1.3);
pop();
}

function smallEye(f1,f2){
  var g = 2.2;
  push();
  translate(f1* BASE,f2*BASE);
rotate(0.1);
  ellipse(0,0,BASE*g*1.1,BASE*g);
pop();
}

Monday, September 25, 2017

json junk

Heh, JSON Generator is a cool way of making fake-y data that follows your JSON structures...

Wednesday, September 20, 2017

trivial php router for local dev and under apache

I wanted to make a PHP app so that I could work on it online and offline, with or without Apache, and that maybe it would be cool to have a centralized controller... do things a bit MVCishly rather than just having a pile of .php scripts (in particular, my first attempt for chart-o-tron did a lot of htaccess hackery to allow for pretty URLs, but the other URLs were all .php which looks pretty janky these days)

The page on the PHP built-in webserver mentions you can run PHP from the command line, and have every request be piped into a router
php -S localhost:8000 router.php
and here's their sample router script:
<?php
// router.php
if (preg_match('/\.(?:png|jpg|jpeg|gif)$/', $_SERVER["REQUEST_URI"])) {
    return false;    // serve the requested resource as-is.
} else { 
    echo "<p>Welcome to PHP</p>";
}
?>
The trouble was when I setup .htaccess to have Apache send all requests to it, the idea of "return false;" doesn't mean anything when Apache has already ceded control. In theory I could have used readfile() to handle PHP stream up static files, but it seemed weird, not leveraging Apache's optimization in serving static content, and a potential security weakpoint.

I decide to put all my static content under /static/ rather than worry about file extensions, or regular expressions to tell Apache to treat .php files differently... It took some fumbling to get the regex quite right:
RewriteEngine On
RewriteRule !^static router.php [L]

I then fiddled with the router script to do the parallel thing when I'm running locally:
<?php
if (preg_match('/^\/static\//', $_SERVER["REQUEST_URI"])) {
    return false;    // serve the requested resource as-is.
} else { 
    echo "<p>Welcome to PHP</p>".$_SERVER["REQUEST_URI"];
}
?>
Seems like a good start. There are other PHP router scripts that are configurable, but I kind of like this low level of control. 

farewell 32-bit iOS apps...

Well, we knew this day was coming... with the release of iOS11, Apple is dropping support for 32-bit apps. I can't blame them, entirely - eventually a company should probably decide to drop the technical weight of supporting everything forever. Still messages like "'ThisApp' May Slow Down Your iPhone" "If no update is available, contact the app developer for more information" were kind of disingenuous. It's stretching it to say it "slowed down the phone" - it would take a moment to setup the legacy libraries, and it's less memory efficient, but really the transition was seamless.

But contact the developer? As if the problem was they didn't know... more "nag the developer and hope that they care about this app even though they didn't figure out how to make it financially viable on an ongoing basis".

If you want to find out what apps you might lose if/when you upgrade to iOS11, go to Settings App, General | About | Applications.

The damage was less bad for me personally than I had feared. I just wanted to take a second to note the apps as I say farewell...

GAMES I'LL MISS

  • ENDI Tank was a playful 3D tank game, taking place in a sandbox. Seems to be a student game, from the École Nationale de Divertissement Interactif , but it was nicely balanced and looked great.
  • Little Master Cricket is a simple physics game from the maker of QWOP. I guess you can play it online (if you still run Flash anyway... sigh.) - balls got pitched in and your batsman had to hit them away and protect the wicket, or whatever cricket is about. It was a fun quick-hit.
  • Truckers was a raucous 16-bit-graphic-flavored semi-driving romp, a bit like Outrun. It's so well polished that I'm surprised it never saw an update. 
  • Big Fat Lies was one of the best "entertain people incuding the driver" car games I've seen. A bit like that part of "Wait Wait Don't Tell Me", two outlandish stories would appear and the current player would have to say which one was false.
  • Galcon was a primitive but fun 2D Real Time Strategy game that I've seen on many platforms, send your hoardes of triangular spaceships to take over planet by planet, turning each into a ship manufacturer to increase the size of your fleet. It was kind of inspiring because I knew it was written in Python/PyGame, back when I thought everything for iPhone had to be in ObjectiveC.
UTILITIES I'LL MISS
  • Weightbot was a terrific little weight tracking tool that made nice little bloops and blurps and clicky noises as you entered your weight. I was using it from 2010 'til this year. Now I use "Weight Record", which has a very similar vibe, but isn't as cute, and with much less satisfying clicks.
  • You've Gotta See This! was a fine bit of photo-stitch software, using the then-new gyroscope to let you wave around the camera and then put together panoramas of the result:
    I have a few similar programs, but haven't yet searched to see if anything does quite as well as this one.
So apps I won't miss: Cracked - "Cracked Lite" has been superior for a long time for reading that great content. CanIStream.it I guess duplicates the website functionality which hasn't felt trustworthy in a while. 20 Questions was another car-able game, mostly just a collection of words to guess. That just leaves iMetronomeTempoTool (heh, kind of a port of an app I wrote for Palm PocketC to tell me what the current BPM are) and SimpleResize - I think these are all utilities I can find replacements for if/when the need arises.

With today's curated online appstores, digital archiving becomes harder and harder- a harsh reality for a lazy retrogamer like myself. Even before this great 32-bit-app purge, there was a great 2D Tank game called "Tron" that Disney commissioned when the new movie came out that has been AWOL for a while. And it's not just Apple - even on Xbox Live, there's a Doritos-sponsored game called "Dash of Destruction" that had such fun with scale - playing on the same board as either a GIANT dinosaur or a tiny delivery van - but if anything ever happens to my hardware I'll probably lose access to the game. For digital historians it's a tough road to hoe.

Monday, September 18, 2017

syntactic high-fructose corn syrup

It's easy for old fogies like me to get a bit cynical about ES6 and all the new syntactic sugar - it can be tough to pick up because if you've only seen it in a webinar or two, but it's not prevalent in the legacy code base you're working with daily, it's easy to forget, and then confusing when you do run into it.

Case in point, this line:
const { urls = {} } = window || {};

Roughly it's saying "set a constant variable (ok, a 'constant') called urls to window.urls if it exists, but don't blow up if window or window.urls doesn't exist."

Besides recognize const vs var, there are three things going on in that tangle:
  1. The good old fashioned, pre-ES6 "short circuit" operator, where you can say
    something = thatthing || {};
    so the right side is thatthing if thatthing is truthy-true otherwise, set to an empty map.

    (huh, surprised the people who love triple equals haven't made triple-or to specifically handle "if this is null or undefined")
  2. Destructuring! The simple case here would be if you had an object called foo with a key bar set to something and a key baz set to something. Then you could say
    var {bar,baz} = foo;
    to get a local var bar and a local var baz set to foo.bar and foo.baz, respectively.

    This actually neatly addresse a weird asymmetry in C-style syntax I blogged about 13 years ago - that it's strange that you pass many things into a function, but you only get one thing out. But now you can do
    var {oneThing, anotherThing} = someFunctionCall();
    and you don't have extract simple variables out of a map object by hand.
  3. Default parameters - for a second
    {urls = {}}
    seemed so strange... I mean I see the value of saying "set urls equal to this if all else fails" but was it a special, one-off syntax just for destructuring? Well, no, now that I think about it... in ES6 you can have
    function someFunc(someParamWithADefault="that default"){ 
    and if nothing is passed in for that first parameter, the first parameter becomes that default. And so we see the syntax used inside the destructuring assignment is borrowing from that generalized default parameter shortcut
So thanks to Dan at work who wrote the code and then explained it to me nicely when asked... he also pointed out I can go to this Babel.js tool to see the concise syntax translated into old school javascript.... in this case
  const { urls = {} } = window || {};becomes

"use strict";
var _ref = window || {},
    _ref$urls = _ref.urls,
    urls = _ref$urls === undefined ? {} : _ref$urls; 
Still a little tough to digest, but it's nice to be able to trace the steps. 

So it seems like Javascript is borrowing the Perl idea of "lets say this more concisely with nifty syntaxes!" but missing Perl's "lets not blow up if we try to pull a value out of an object that doesn't really exist". 

Sunday, September 10, 2017

put something back into the world

Steve Jobs over dinner with Steven Levy:
"I look at myself as [sort of trapeze artist, without a net] if anything. But it's a way of expressing feelings about, a group of feelings. Wanting to put something back into the world. You know we're constantly taking. We don't make most of the food we eat, we don't grow it, anyway. We wear clothes other people make, we speak a language other people developed, we use a mathematics other people evolved and spent their lives building. I mean we're constantly taking things. It's a wonderful ecstatic feeling to create something and put it into the pool of human experience and knowledge.
The interview transcript is an appendix to a new edition of his older book about the development of the Macintosh, "Insanely Great"

One thing the book mentioned was John Sculley pricing the late-80s Mac a bit high, going for profit margin rather than marketshare. I guess a version of that strategy is working well for Apple now, taking something like 90% of the mobile phone industry profits, but still visions of a world where the Mac had early, Apple II like penetration, and where every college kid had one rather than just the artsy ones... if HyperCard had been in the hands of even more people...

(Of course, looking around in the environs of Boston tech and Cambridge coffeeshops, it's astounding that only 1 in 10 PCs are by Apple - they seem to be omnipresent)

Getting back to the Steve Jobs quote, thinking of what I try to add to that pool. I guess except for "JoustPong" (heh) my best bet is helping people to calm down about death via So, You're Going to Die.


Sunday, September 3, 2017

css-only icons

Keeping my eyes open for icon packs that are cheap, both in terms of complexity/files to load, and in terms of cost (though i don't mind spending $10 or so I guess.)

Icono pure CSS icons are pretty dope, but it's weird there's no obvious "edit" (like maybe a pencil to a piece of paper?) Also they're not easy to resize I guess. Maybe I should keep looking for future projects, but for my current project it'll do.

Saturday, September 2, 2017

i teach you the spongeman

A while ago my erstwhile debating partner introduced me to Rapoport's Rules, guidelines for criticizing the argument of an opponent. As formulated by my favorite philosopher Daniel Dennett, they go:
  1. You should attempt to re-express your target’s position so clearly, vividly, and fairly that your target says, "Thanks, I wish I’d thought of putting it that way."
  2. You should list any points of agreement (especially if they are not matters of general or widespread agreement).
  3. You should mention anything you have learned from your target.
  4. Only then are you permitted to say so much as a word of rebuttal or criticism.
Another term for this is "steelmanning" - in contrast to "strawmanning", where you knock down a lightweight representation of the opposing argument that's designed to be knocked down, here you make an effort to really understand and then gird it in rhetorical steel and state it back to them.

On some levels the rules' concept is appealing, but also - unlikely, I guess I'd say, for people who have are arguing sincerely. If you could whole-heartedly restate your partner's (or as the rules put it, "target's") view, you'd pretty much have to be believing it yourself. That "Thanks, I wish I'd thought of putting it that way" bit is also weirdly condescending - your displayed mastery of the domain is such that your "target" will humbly thank you for your cleverness of the restatement? For something that you still don't believe? What kind of insincere sophistry is that? Like a suit of armor, I think this kind of steelman will ring hollow.

My erstwhile buddy didn't really grasp my objections until he listened to Hannibal Buress on the Sam Harris podcast. (Admittedly Buress might be a little drunk, but I appreciate his sincere points) Around 29:00 minutes in, Sam Harris says
Here's a bet, here's a bet: I could summarize your view of me in a way that you'd agree with. You couldn't return the favor. You want to take that bet? I'm absolutely sure I can articulate how you view your side of the conversation in a way that you'd sign off on. I have absolutely no faith that you could do the same for me. That's a problem, we're not successfully communicating.
My buddy had an even strong reaction against Harris there than I did, that he saw Harris using the "I can see your side" concept as a bludgeon.

My counter-proposal was "spongemanning". The best we can do is try to absorb the other person's argument, then wring ourselves out, restating the argument as best we can, and have our partner comment on the drippings, to see how much of the salient info we had actually taken in. Spongemanning offers more substance than the superficialities of steelmanning, and it is more respectful than steelmannings "anything you can think, I can think better".

At its very best it invites participants to think about where their partner is coming from, and what are the headwaters of their current flow. (At the risk of straining the wet metaphor.) One of the few things I like about Ayn Rand is her alleged greeting of "What are your premises?" It's rather belligerent, but it gets to the heart of why sincere people who keep faith in the methods of rationality and discourse as a way of understanding the universe can still disagree... they have different starting assumptions and then differing concepts on what is best prioritized in life. By trying to absorb what your opponent is saying, you might better identify and catalog those sticking points - fundamental areas of disagreement where "agreeing to disagree" isn't throwing out the whole kit and kaboodle.

Behold: the spongeman! (With normal, double-tube-shaped pants)

Thursday, August 31, 2017

count your secular blessings

A blog I like, Lost in Mobile, sometimes parlays thoughtful comments into new articles. Here's a bit from a comment I made on an entry on folks being jaded about smartphone improvements:
Sometimes I still get myself a little frisson of excitement about how cool the little gadget I'm carrying is, how chuffed I am to have my Todo list all organized on it, and my music all sorted and at the ready, etc. I think that's a weird kind of consumerist mindfulness. I'd seriously suggest people do that – take inventory of the blessings bestowed upon you by an engineering savvy society – from crisp clean water, hot showers, and flush toilets, to public health saving us from a bajillion ailments, to our crazy ability to travel at 60 mph like it ain't no thing and hundreds of miles faster than that for a reasonable sum, to the way our little gadgets have access to SO much information, and provide (for worse but generally better) a constant lifeline of contact with our loved ones. Be thankful for all this stuff, because it's well-nigh miraculous.
Full ramble here...