Monday, October 24, 2022

yeah but it's not CHEATING cheating right?

 I tend to play a daily wordle, comparing notes with coworkers. 

Every once in a while I have 3 letters green, but no idea what goes in the other two places. Small enough that it's possible yet annoying to run the permutations in my head. So earlier I would write little scripts to do that which I finally decided to enhance with a UI...

it was interesting to generalize the hardcoded cases from earlier:

function permutate(){

 const bads = window.bads.value.toLowerCase();

 const goods = alphabet.split('').filter(x=>bads.indexOf(x) === -1);

 const word = window.word.value.toLowerCase();

 const parts = word.split('_'); 

 if(word.length !== 5 || parts.length !== 3) {

    alert('expected word to be 5 letters with two _s');

    return;

 }

 const perms = [];

 goods.forEach(a=>{goods.forEach(b=>perms.push(`${parts[0]}${a}${parts[1]}${b}${parts[2]}`))});

 window.results.innerHTML = perms.join('\n');

}

Used fun shortcuts like an element with an id is available at window.id, and then it was another good case of fun with split/join/filter/forEach.

(Pushing to an array outside of the loop seems a little less graceful, but wasn't sure how else to handle the nesting of it.)

So it's definitely sort of cheating, though much less so than using one of the sites that knows the words in Wordle...

Friday, October 21, 2022

switching modes in gmail

 I've used gmail for a long time, since 2004. For a long time I really loved its "Important + Unread" vs "Everything Else" feature; that really got to the heart of what I wanted in a robot sorting my email.... "this is probably worth looking" vs "this can probably be skipped" (this is independent of gmail's spam folder.)

I stuck with it even after it adopted a new paradigm (I think I remember it lifting the feature from a different trial mail service) of sorting mail into categories - Primary, Promotions, Social, Update , and Forums. But I still preferred the simpler "look at this or don't".

Well, for the past few months the "Important" categorization has really been slipping. And I was started to feel overwhelmed, and "inbox zero" (even for just "important and unread") was getting harder and harder to achieve. 

So for a week or so I switched to the categories... and you know, I think it helps a lot. It feels like I'm spending less effort to get to a true inbox zero (not just "important"). 

It lets gmail sneak a few more ads in there, but considering how long I've been using them as a free service, it's not bad. And unlike many the privacy aspect doesn't bug me too much.

Sometimes I wish I had been more steadfast in using an email address I control vs handing out my gmail... (especially since I used the ridiculous semi-gamer-handle kirkjerk...)

Wednesday, October 19, 2022

js array functions are so pleasant

Like yesterday's use of reduce(), there is something absolutely pleasant about a nice little set of JS array functions (filter, map, reduce, join) - like a programmer's mental ASMR. (And use of fat arrow functions make it even cleaner...)

Here's a shtick I did for an overly simplistic "Convert To Title Case" function:

const titleCase = (words) => words?.split(' ')
      .map(word => word.substring(0,1).toUpperCase()
                   + word.substring(1))
      .join(' ');

console.log(titleCase(null));

console.log(titleCase("this  is a test"));

console.log(titleCase("ok")); 

Just so charming.

Tuesday, October 18, 2022

trivial javascript templating with reduce()

 At work we have a translation system that has strings like this:

"Welcome home, ${name}"

"Bienvenido a casa, ${name}"

"willkommen zu hause ${name}"

etc. 

Now those look like javascript template strings, but since it's at run time not compile, you can't just jam it in with backticks....(and also you probably want to have a little map of key value pairs to use)

Apparently other systems we use have a template system for the i18n stuff - you could just include a maplike object of key/value substitutions to make - but ours didn't have that and it wasn't clear it would be easy to include, given all the gatsby etc environmental weirdness it has to handle

Being a properly lazy programmer, I found this example of code to possibly steal. It can even handle stuff like 'Example with math: ${2 +2}' and get you that 4. But that seemed like overkill plus triggered my 'possible security risk' spider sense - that whole "new Function()" bit made me think I was too lazy or not smart enough to know if it was safe to use.

Really, I just had a Javascript 101 / interview question on my hand... "how can I replace all ${FOO} instances in a string with the corresponding values from a maplike object?". But one insight was, I shouldn't treat it like a fancy regex for every instance of ${ }.... I can just run against the keys of maplike thing that has the substitutions I care about.

Interestingly (to me) the best candidate array helper function was "reduce()", against the array of keys from the maplike - the initial value is the template, then the function takes in the template (with applied substitutions) as the previous value, and the current value is actually the key to do a replaceAll with... thus...

const templater = (message,replacements) =>
Object.keys(replacements).reduce((stringSoFar, key) =>
stringSoFar.replaceAll(`\${${key}}`, replacements[key]), message);

And with a little tester 

const translation = "${FOO} x ${FOO} y ${BAR} z ${FOO} omega FOO BAR";
const replace = {"FOO":"foofoo","BAR": "barbar"};

console.log(templater(translation, replace));

which gave me

foofoo x foofoo y barbar z foofoo omega FOO BAR

as expected

Thursday, October 13, 2022

automated visual regression testing across devices via browserstack and percy

 My company is looking into using Browserstack's Tool Percy for automating testing, plugging it into CICD so that PR's all do a snapshot audit across components and pages.

It's a win - and I love testing holistic final products, not reductionistic units, though I worry it doesn't cover interactions very well... 

Also I worry about the cost. One plan has 200,000 snapshots but I worry that might be exhausted more quickly than you expect, because of the geometrical permutations from different components and pages, different browsers and devices, and multiple PR (especially if each commit in an open PR retriggers the build process...) Feels like when you have a cellphone plan without quite enough data...

Friday, October 7, 2022

github note - ignore whitespace (now with UI bit)

Around 5 years ago I posted this tidbit. and it came up again today:

When doing a Pull Request via github you can add a ?w=1 to the end of a url e.g.  https://YOURCOMPANYSITE/BRANCH/pull/1785/files?w=1

I reposted after sharing it with a coworker who didn't realize it existed, and a different coworker mentioned there's a UI for it: (that forces a reload because it's just a wrapper for the URL)

anyway, this obviously makes it easier to confirm code like where you're making a split or other conditional test permanent, and the only difference is of a big code block is indentation from when it was a conditional...

Thursday, October 6, 2022

gatsby copy files as last step of build

My employer has the same site in different locales, served by one main Gatsby-powered project. 

We wanted to have a different "robots.txt" for each process.... our gatsby-config.js had something that LOOKED like it was copying robots.txt in particular, but our use of gatsby-plugin-copy-files wasn't actually doing anything... it was confusing because the file still seemed to be copied, but apparently as part of a general "copy from static/ to public/" function - and overall it was hard to track what Gatsby was doing when.

I didn't do a deep dive into Gatsby, but this github entry seemed to be covering similar ground... the secret was to make a gatsby-node.js, and then do this:

const path = require('path');
const fs = require('fs-extra');

const envLocale = process.env.GATSBY_LOCALE || 'en-us';

/**
 *  Copy a locale-specific robots.txt file into place
 **/

exports.onPostBuild = () => {
  const src = path.join(
    __dirname,
    `/src/content/robots/${envLocale}/robots.txt`,
  );
  const dest = path.join(__dirname, `/public/robots.txt`);
  fs.copySync(src, dest);
};

It always feels fraught banging on tech someone else put into place, and you've never done a "hello world" with or anything. And gatsby is "interesting" especially in developer mode, where its often copying files over. But this seems to get the job done.

Saturday, October 1, 2022

best you may not need jquery - document ready

 I have long appreciated the site You might not need jQuery - it does a great job of bridging the gap from jQuery to vanilla.js. (The two are really quite similar... for my money the biggest similarity is "You don't need a build system".) 

One thing I look up a lot: document.ready

$(document).ready(function () {});

which can become

function ready(fn) {
  if (document.readyState !== 'loading') {
    fn();
  } else {
    document.addEventListener('DOMContentLoaded', fn);
  }
}

More as I end up using it...