<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2009-05-20:374172</id>
  <title>Rich and Strange Aeons</title>
  <subtitle>mindstalk</subtitle>
  <author>
    <name>mindstalk</name>
  </author>
  <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom"/>
  <updated>2022-06-22T01:01:46Z</updated>
  <dw:journal username="mindstalk" type="personal"/>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:601942</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/601942.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=601942"/>
    <title>bugbear debugging</title>
    <published>2022-06-22T01:01:46Z</published>
    <updated>2022-06-22T01:01:46Z</updated>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">It is commonly believed that when dealing with an ornery bug, just explaining the problem out loud to someone else often grants insight. "--oh, I see it now, sorry to bother you."  So much so that, supposedly, one senior engineer required juniors to explain their problem first to a teddy bear, the 'bug bear', and only if that failed could they bother him.&lt;br /&gt;&lt;br /&gt;I haven't actually used this much. Mostly been on my own, and my default approach to bugs is &lt;b&gt;more logging&lt;/b&gt;.  But I was playing with TypeScript and Koa today, and had a problem that didn't work for: the main code worked fine, but if authentication failed, the server seemed to never respond to the caller.&lt;br /&gt;&lt;br /&gt;I was about to find a senior active on Slack, to ask for help, when I thought of the bugbear.  I did not have a teddy bear, and I don't think I even said anything out loud, but I did go line by line, trying to mentally verbalize what was happening and what the point was.  And yes, found something suspicious: "ctx.response = 401", which looks like it's trying to set a status code but is clobbering the response object.  And yes, "cts.response.status = 401" fixed it.  Voila!  No seniors disturbed.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=601942" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:582101</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/582101.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=582101"/>
    <title>python JSON datetime at last</title>
    <published>2021-08-26T16:47:56Z</published>
    <updated>2021-08-26T16:47:56Z</updated>
    <category term="programming"/>
    <category term="python"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">content warning: geeky computer stuff&lt;br /&gt;&lt;br /&gt;At work I have a common flow of Python code querying MySQL and dumping results into JSON.  This works great except our tables tend to have columns for create and modify dates.  And Python's json library won't convert datetime types to string, so dumping the result of "SELECT * FROM" errors.  And I've had bits of ad hoc code to remote datetime values, then a little function for it, but it was still a pain.  Especially today, when for stupid VPC reasons I'm writing a simple generic SQL service.&lt;br /&gt;&lt;br /&gt;In annoyance I tried searching again and found, buried in the middle of a stackoverflow with answers about subclassing and shit:&lt;br /&gt;&lt;br /&gt;json.dumps(thing, default=str)&lt;br /&gt;&lt;br /&gt;Bam, done.  The function passed to 'default' gets invoked on anything that errors at first.  And in Python 'str' works on pretty much anything.&lt;br /&gt;&lt;br /&gt;If I cared about the exact format I could write a function that inspected type and converted dates (or just assume datetime is the only cause of errors so just invoke a method when triggered), but str is fine for now.&lt;br /&gt;&lt;br /&gt;Soooo simple.  Thanks, python, and stackoverflow person who gave the simplest answer.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=582101" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:570790</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/570790.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=570790"/>
    <title>more Javascript</title>
    <published>2020-10-22T21:34:12Z</published>
    <updated>2022-02-04T02:17:10Z</updated>
    <category term="javascript"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">New Job has me learning JS and Node.js.  I have learned that some of my earlier complaints (see tag) have been improved by later developments (or ones extant at the time that I hadn't found.)  Like 'var' variables have function scope (useful concept; I think it applies to Python), but you can get block scope (One True Way) by using 'let' instead.  I don't think I knew that simply assigning to an undeclared variable creates a global (dear gods) but JS borrowed 'use strict'; from Perl, which shuts that off.&lt;br /&gt;&lt;br /&gt;JS strikes me as a shitty half-assed core language which is trying to grow its way into respectability.  Unfortunately it has 25 years of shitty web code to have to be backwardly compatible with.&lt;br /&gt;&lt;br /&gt;No wonder there are multiple languages to use instead, that compile down into JS.&lt;br /&gt;&lt;br /&gt;Today I accidentally discovered another WTF.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
&amp;gt; l=[1,2,3]
[ 1, 2, 3 ]
&amp;gt; for (v in l) console.log(typeof(v));
string
string
string
undefined
&amp;gt; for (v in l) console.log(v);
0
1
2
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So in a way this makes sense.  "for in" iterates over the properties/keys of an object, which for an Object (dictionary-ish) are names.  The properties of an Array are numbers, but in a 'for in' context, they could be strings.&lt;br /&gt;&lt;br /&gt;OTOH, stripped of rationalization: the indices of an array are numeric, and yet they're strings in this iteration case.  ffffuuuuu.&lt;br /&gt;&lt;br /&gt;Of course, JS coerces between numbers and strings at least as fluidly as Perl does.&lt;br /&gt;&lt;br /&gt;I found this behavior by accident, I was printing 'v[0]' thinking I was using 'for of" (which iterates over the values of an Array) when I wasn't, and I got numbers rather than letters or 'undefined', which is what you get if you try&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
&amp;gt; n=4
4
&amp;gt; n[0]
undefined
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=570790" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:566414</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/566414.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=566414"/>
    <title>watermarking ebooks</title>
    <published>2020-08-01T08:23:31Z</published>
    <updated>2020-08-01T08:23:31Z</updated>
    <category term="security"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">I've bought RPG PDFs.  They're never DRMed, but from DriveThruRPG they're allegedly watermarked.&lt;br /&gt;&lt;br /&gt;I've bought DRM-free ebooks.  Watermarking isn't mentioned, but I wonder if you could.  I assume you could stow an extra blob in an EPUB file.  What would you stow?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
{  
  'customer': "Jane Doe",
  'title': "This book is awesome",
  'salt': "DEIFEFIGDBYDEADBEEF"
}
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Encrypt that with a publisher secret key, stick it in the EPUB.&lt;br /&gt;&lt;br /&gt;What does that get you?  If someone is lazy and uploads their book to public places, you know where it came from.  (You don't know for sure they did it -- maybe a hacker plundered their hard drive.)  The encryption means someone can't forge an upload, pretending it came from someone else.  The salt complicates known-plaintext attacks trying to recover the secret key.&lt;br /&gt;&lt;br /&gt;Most ebooks have at least one image, the cover.  You could use steganography to stash the blob there; it's encrypted text so should fit.  Given that it's an encrypted blob, people may have trouble knowing whether you did anything at all, until you reveal your process.&lt;br /&gt;&lt;br /&gt;After which, non-lazy pirates could delete the blob, or scramble where you're hiding the cover image.  The watermark is hardly foolproof.  But it's cheap.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=566414" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:564767</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/564767.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=564767"/>
    <title>JS surprise</title>
    <published>2020-07-15T02:39:41Z</published>
    <updated>2020-07-15T02:39:41Z</updated>
    <category term="programming"/>
    <category term="javascript"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">I was looking at my 'programming' tag posts and found a bunch of 3 years ago, complaining about odd features of JavaScript.  I kind of remember them now, but if you'd asked me yesterday if I'd ever taught myself JavaScript I would have said 'no', not remembering doing so.&lt;br /&gt;&lt;br /&gt;I was prompted by an interviewer having looked at this blog.  I wonder what he thought about my saying I hadn't taught myself JS...&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=564767" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:563406</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/563406.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=563406"/>
    <title>covid new case rates by country</title>
    <published>2020-06-27T05:55:56Z</published>
    <updated>2020-06-27T06:11:06Z</updated>
    <category term="programming"/>
    <category term="covid"/>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">I've started following &lt;a href="https://www.worldometers.info/coronavirus/#countries"&gt;https://www.worldometers.info/coronavirus/#countries&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;which gives daily new cases per country, and total cases per population, but not new cases per population.  I wanted to find that out, and more explicitly than doing math in my head.  So I wrote a web scraper.  I have concluded that writing a scraper should be a last resort, it was a shitty experience.  But I got what I wanted: &lt;a href="https://mindstalk.net/covid_scrape/new.html"&gt;https://mindstalk.net/covid_scrape/new.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is a one-day snapshot, not regularly updated.  A few countries:&lt;br /&gt;&lt;br /&gt;US: 143 new cases per million people.&lt;br /&gt;Sweden: 30&lt;br /&gt;Iran: 30&lt;br /&gt;UK: 20&lt;br /&gt;Austria: 5&lt;br /&gt;Australia: 1.45&lt;br /&gt;Japan: 0.7&lt;br /&gt;Hong Kong: 0.4&lt;br /&gt;New Zealand: 0.2&lt;br /&gt;&lt;br /&gt;Granted those last two have single digit new cases, so could jump around from an extra person getting sick.  Japan had 87 new cases, that's a significant number.  The US, well, had almost 3x as many new cases in one day as Japan has had total cases...&lt;br /&gt;&lt;br /&gt;I'd like to leave the country but I don't think there's anywhere that would let me in.  Trapped in the Plague Zone.&lt;br /&gt;&lt;br /&gt;Edit: a friend found &lt;a href="https://91-divoc.com/pages/covid-visualization/"&gt;https://91-divoc.com/pages/covid-visualization/&lt;/a&gt;&lt;br /&gt;lower half has a graph of this stuff, though it seems to leave out the really low countries.  I haven't played with it much yet.&lt;br /&gt;&lt;br /&gt;See, this is why I don't have a portfolio of big programming projects; almost anything I think of has already been done.&lt;br /&gt;&lt;br /&gt;Edit 2: yeah, the presentation isn't exactly what I want -- I don't see an option for table data.  OTOH it shows a 1-week average, which is more robust than daily results, though can also be slow to show exponential takeoff.&lt;br /&gt;&lt;br /&gt;Last 7 days average 102 for the US, with 136 as last point; Japan average 0.6.  NZ 0.4.  I can't even get it to show me data points for Hong Kong.  Sweden 98! -- I must have snapped a really low data, or a partial report.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=563406" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:561516</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/561516.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=561516"/>
    <title>my first ever Python bug</title>
    <published>2020-06-14T04:01:28Z</published>
    <updated>2020-06-14T04:01:28Z</updated>
    <category term="programming"/>
    <category term="python"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Years and years ago, when Perl was still the dominant scripting language, with Python and Ruby nipping at its heels, and CPAN was where you would look for cool libraries, I wrote my first Python program.  I don't recall what it did, whether it was meant to do something useful or just do something like "10 9 1 blastoff" as a test, but I do know that it looped based on a command line parameter.  And that it didn't work, running nigh-forever when it had a parameter of '20' and should stop after 20 times.  It took me like 20 minutes to figure out what was wrong.&lt;br /&gt;&lt;br /&gt;I can replicate the basic problem:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
import sys
count = 0
while count &amp;lt; sys.argv[1]:
    print(count)
    count += 1
else:
    print("Blastoff!")
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And the behavior still replicates -- if you run it in Python 2.  In Python 3, you'll get&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
TypeError: '&amp;lt;' not supported between instances of 'int' and 'str'
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Because sys.argv is a list of strings.  Thing is, Perl is a very accommodating language; the equivalent code in Perl will just work, as I well knew.  Or rather, Perl has separate comparison operators for numeric and string values, so this code, using '&amp;lt;', would quietly try to convert sys.argv[1] into a number for comparison with 'count'.  (If you wanted lexicographic comparison, you would use 'count lt sys.argv[1]', except of course it would be more like '$count lt $argv[1]' or something; anyway, there the value of $count would be converted to a string for comparison.)&lt;br /&gt;&lt;br /&gt;I remember being very put out.  Though I did go write a 'real' script in Python, and showed it to my boss, who was able to read and understand it with no Python knowledge.  Go go executable pseudocode.&lt;br /&gt;&lt;br /&gt;These days, on the rare occasions I poke at Perl, I'm more likely to be annoyed by the lack of a REPL, or easy ways to print nested data structures, or the quirky way function arguments are handled.  Perl still does some things better ('use strict;') but I don't miss it.&lt;br /&gt;&lt;br /&gt;But dang, that bug.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=561516" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:556771</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/556771.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=556771"/>
    <title>wtf Python</title>
    <published>2020-04-13T03:24:25Z</published>
    <updated>2020-04-13T03:24:25Z</updated>
    <category term="programming"/>
    <category term="python"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">I was writing some code, in a file called 'code.py'.  I tried adding doctests and running them; this would hang, or complain about circular imports.  It seems that 'import doctest' will run a file in the directory called 'code.py' -- e.g. make a 'code.py' file like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
while True:
    pass
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;start python, import doctest, and watch it hang.&lt;br /&gt;&lt;br /&gt;This seems poor, and undocumented.  Probably I should file a bug later.&lt;br /&gt;&lt;br /&gt;I guess I have a new candidate for interview questions about problem solving.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=556771" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:556135</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/556135.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=556135"/>
    <title>Noldor Monte Carlo: CORRECTION</title>
    <published>2020-04-10T01:01:58Z</published>
    <updated>2020-04-10T05:35:37Z</updated>
    <category term="programming"/>
    <category term="tolkien"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">If you dive deep into Tolkien fandom, a recurring question is "How many elves were there at any time?"  Now, Tolkien cared a lot about languages and moon phases, but his attitude toward demographics or non-human food production would be an insult to good handwaving, so this is hard to answer well.  The one hard number is that Turgon brought 10,000 troops to the Battle of Unnumbered Tears.  We also have a couple of proportions, and then a whole mass of "the greater part".&lt;br /&gt;&lt;br /&gt;Also, in the older Fall of Gondolin, 12 named companies muster to the defense of Gondolin; a company of around 800 people would give 9600 defenders.  Under the circumstances you'd think *everyone* who could fight would be...&lt;br /&gt;&lt;br /&gt;In the past I've just made a range of estimates of how 10,000 relates to the population of Gondolin and applied averages to the rest, but I thought I would try estimating all the ranges.  At which point a Monte Carlo simulation is more useful than just multiplying minima and maxima.  Since I wanted the answer ASAP I did it in straight Python, not R or Octave or some library.  Being lazy, I used uniform distribution for the ranges.&lt;br /&gt;&lt;br /&gt;Kind of my first non-class Monte Carlo?  Apart from some old C programs that were simply simulating dice outcomes like 3d6 and "4d6, top 3" and such.&lt;br /&gt;&lt;br /&gt;Edit: whoops!  I found a bad error in my original code.  If I'm trying to go from 10,000 Noldor+Sindar soldiers to a "Noldor in Valinor" population, I need to *multiply* by the fraction of Noldor in Gondolin, not divide!&lt;br /&gt;&lt;br /&gt;Instead of pasting code I'll just link: &lt;a href="https://mindstalk.net/noldor.py"&gt;https://mindstalk.net/noldor.py&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The first thing I learned is that when you're doing 9 divisions, the small-divisor outliers meant that I needed  lot more bins than I thought at first.&lt;br /&gt;&lt;br /&gt;95% likely over 50,000,  95% likely under 1 million; 90% likely over 70,000, 90% likely under 680,000.  90% confidence interval is 50,000-1 million, 80% confidence is 70,000-680,000.&lt;br /&gt;&lt;br /&gt;Possible range is 8000 -- definitely too small -- to almost 9 million.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=556135" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:555278</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/555278.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=555278"/>
    <title>Zoom bombing</title>
    <published>2020-04-06T21:11:44Z</published>
    <updated>2020-04-06T21:11:44Z</updated>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">One downside of the convention was some assholes 'bombing' the performance.  I wondered how it was so easy to find us; web scraping or something?  Probably not!&lt;br /&gt;&lt;br /&gt;&lt;a href="https://krebsonsecurity.com/2020/04/war-dialing-tool-exposes-zooms-password-problems/"&gt;https://krebsonsecurity.com/2020/04/war-dialing-tool-exposes-zooms-password-problems/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The unique part of a Zoom ID is just a 9 to 11 digit number, 9 in my experience, so you can just try random URLs until you get a hit.  This isn't like cracking a specific password, this is like the birthday paradox, where you keep trying until you hit *something*.  And with 200 million daily users now, the odds of a billion numbers are looking pretty good.&lt;br /&gt;&lt;br /&gt;So there are fixes like requiring a password, or Waiting Rooms.  Why doesn't Zoom just increase the ID size?  Someone said that they want URLs that can be easily read out over the phone (this actually happened to me on one job interview.)  I don't really see how 16 digits would be much worse than 9 or 11.  But I note that if you add in lower case letters (so you don't need to specify case), and even drop a few characters as too similar (1 and l), you can get 1e15 possibilities in 10 characters. That's 1 million times sparser than 9 digits.  And the war dialers can't just throw GPUs at the task like password testing, they need to make network connections to zoom.us to try URLs.&lt;br /&gt;&lt;br /&gt;Relatedly, the odds of guessing a US Social Security number in use by someone are pretty good.  With a few more digits, they would not be.  (Your odds of guessing an active credit card number, 16 digits, are probably not good, though the space is limited by internal structure or checksums in ways I don't know.)&lt;br /&gt;&lt;br /&gt;Also relatedly, when generating strings of random letters for public exposure, there's the chance of creating funny or offensive strings, like JkmCatp0op.  One idea I saw was to not use vowels, though that still leaves the 'vowels' of 0, 4, and 1 (O, A, I).  If you limit yourself to lower case consonants plus 7 numbers, that's 28 characters, and 10 of them have 2e14 possibilities.  Adding one character puts you back at 8e15, 12 at 2e17.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=555278" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:553405</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/553405.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=553405"/>
    <title>computer detective work</title>
    <published>2020-03-25T20:52:03Z</published>
    <updated>2020-03-25T21:30:07Z</updated>
    <category term="programming"/>
    <category term="computer"/>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">My phone was slow, so I rebooted it.  And logged in again to my shell server.  And got an error message about now finding 'zsh-syntax-highlighting/' I hadn't seen before.  And my shell didn't have highlighting.  I connected to the server's screen session and confirmed that yes, old shells have highlighting.  Something's definitely wrong!&lt;br /&gt;&lt;br /&gt;'ls', and I find 'zsh-syntnax/' [sic].  WTF?  Why is that?  Did something go horribly wrong with my last OS upgrade?  Have I been hacked and pranked?&lt;br /&gt;&lt;br /&gt;Fortunately I keep a really deep shell history, and found&lt;br /&gt;&lt;br /&gt;'mv zsh-syntax-highlighting zsh-syntnax' from 9 days ago.&lt;br /&gt;&lt;br /&gt;That answers how, but not who or why; I don't remember doing that!&lt;br /&gt;&lt;br /&gt;But the history provides context, several other 'mv' commands renaming long filenames to shorter ones.  Aha, I do remember doing that!  I wanted 'ls' output to fit into more columns.  So I did that to this directory without considering that some part of my shell configuration was actually using it.  Whoops!  And somewhat excusable, once my configuration is set up I don't have to twiddle with it much, I have aspects that are 25+ years old yet contributing positively to my experience.&lt;br /&gt;&lt;br /&gt;One quick rename and edit of .zshrc to use the new name, and all is well again.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=553405" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:548197</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/548197.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=548197"/>
    <title>self-driving car skepticism gloat</title>
    <published>2019-12-31T22:29:46Z</published>
    <updated>2019-12-31T22:37:04Z</updated>
    <category term="ai"/>
    <category term="self-driving cars"/>
    <category term="cars"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>14</dw:reply-count>
    <content type="html">When self-driving cars first started getting talked about, like 10 years ago, many people were enthusiastic and anticipatory.  I was skeptical, because as someone who walks around dense cities, driving safely and effectively in such felt like a human-complete AI problem, needing theory of mind, social interaction, and a large amount of adaptation to unforeseen circumstances.&lt;br /&gt;&lt;br /&gt;Also because while in some things like chess or Go, rather dumb computers beat humans through powerful search, a more common AI pattern is that a fairly simple system can get 60-90% of human performance, but then stalls despite a lot of effort.  Which is fine when you're making models for targeting direct mailing, and poorer performance can be balanced by much faster turnaround time and it's just moderate amounts of money at stake anyway.  Less fine when even a missing 1% of performance may mean people die, or alternatively that traffic is frozen as cars can't figure out how to safely push through busy streets.&lt;br /&gt;&lt;br /&gt;(The direct mailing example is from my first full-time job; we could build a decision tree, to predict response rates to a direct mailing, that was said to be 60% of a hand-crafted model but took a few hours instead of a few months to create.  A machine translation course in grad school included various systems that could do 60-95% as well as humans, on fairly narrow word tests, but improving that was Hard.  Statistical translation, rule-based, hybrid, all stalled.)&lt;br /&gt;&lt;br /&gt;Basically an application of the Pareto principle: 20% of the work can get you 80% of the performance.  Except it might be more like 1% of the work gets you 80% of the performance; since we don't *have* human-equivalent AI in most of these domains, we can't even say how much work it actually takes.&lt;br /&gt;&lt;br /&gt;Early articles were along the lines of "we're making lots of progress! (but can't drive in the rain or snow and are tested mostly in low-density sunlight)", which for some people sounded like "we're almost there but for a bit more work" but to me sounded like "we're already spending years on the *easy* stuff, imagine what the hard stuff will be like."&lt;br /&gt;&lt;br /&gt;More recent articles have been more like "wow, this is harder than we thought", with even the executives in charge of developing and selling this stuff saying like "thirty years away" or "&lt;a href="https://www.cnet.com/news/alphabet-google-waymo-ceo-john-krafcik-autonomous-cars-wont-ever-be-able-to-drive-in-all-conditions/"&gt;never&lt;/a&gt;" or "&lt;a href="https://www.nytimes.com/2019/07/17/business/self-driving-autonomous-cars.html"&gt;far in the future&lt;/a&gt;", or "&lt;a href="https://www.businessinsider.com/self-driving-cars-fully-autonomous-vehicles-future-prediction-timeline-2019-8?r=US&amp;amp;IR=T"&gt;decades away&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;Singapore reportedly has deployed them, as someone on Facebook likes to keep saying, but a friend there observed various caveats: 10 MPH, a bounded area, not mixed with other cars, safety driver, and attendants trying to shoo pedestrians out of the way.  Also &lt;a href="https://www.businessinsider.com/600-miles-public-roads-close-singapore-test-self-driving-cars-2019-10"&gt;see&lt;/a&gt;.  And this is the state of the art!&lt;br /&gt;&lt;br /&gt;So, "ha ha!"&lt;br /&gt;&lt;br /&gt;I'll also include a FB &lt;a href="https://www.facebook.com/mindstalk/posts/10110754433895129"&gt;thread&lt;/a&gt; I made two years ago about predictions, and include just one example of receding predictions:&lt;br /&gt;&lt;br /&gt;2014: Volvo promises fully self-driving cars by 2017, 3 years later.&lt;br /&gt;2017: Volvo promises partial self-driving cars by 2021, 4 years later.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=548197" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:513680</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/513680.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=513680"/>
    <title>Python is annoying</title>
    <published>2019-02-07T14:53:14Z</published>
    <updated>2019-02-07T14:53:14Z</updated>
    <category term="programming"/>
    <category term="python"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Our code works with binary data (hashes/digest) and hexstring representations of such data, a lot. It was written in Python 2, when everything was a string, but some strings were &amp;quot;beef&amp;quot; and some were &amp;quot;'\xbe\xef'&amp;quot;&lt;br /&gt;&lt;br /&gt;Then we converted to Python 3, which introduced the 'bytes' type for binary data, and Unicode strings everywhere, which led to some type problems I had figured out, but a recent debugging session revealed I had to think about it some more.  Basically we can now have a hexstring "beef", the bytes object b'\xbe\xef' described by that hexstring... and the bytes b"beef" which is the UTF-8 encoding of the string.&lt;br /&gt;&lt;br /&gt;In particular, the function binascii.hexlify (aka binascii.b2a_hex) which we used a lot, changed what it returned.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
Python 2:
&amp;gt;&amp;gt;&amp;gt; binascii.a2b_hex("beef")
'\xbe\xef'
&amp;gt;&amp;gt;&amp;gt; binascii.hexlify(_)
'beef'

Python 3:
&amp;gt;&amp;gt;&amp;gt; binascii.a2b_hex("beef")
b'\xbe\xef'
&amp;gt;&amp;gt;&amp;gt; binascii.hexlify(_)
b'beef'

vs.
&amp;gt;&amp;gt;&amp;gt; binascii.a2b_hex("beef")
b'\xbe\xef'
&amp;gt;&amp;gt;&amp;gt; _.hex()
'beef'
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I found it easy to assume that if one of our functions was returning b"beef" and the other "beef" that they were on the same page, when really, not.&lt;br /&gt;&lt;br /&gt;Bunch of examples in the cut.&lt;br /&gt;&lt;br /&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://mindstalk.dreamwidth.org/513680.html#cutid1"&gt;Grah Python&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=513680" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:495172</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/495172.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=495172"/>
    <title>logging thoughts</title>
    <published>2018-05-16T20:33:09Z</published>
    <updated>2018-05-16T20:33:09Z</updated>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>4</dw:reply-count>
    <content type="html">One of the first things I did for work was implementing a better logging system, based around the Python logging library, which introduced me to the world of DEBUG, WARNING, INFO, ERROR.  Useful, but something felt off from my expectations.  I think I've finally pinned that down.&lt;br /&gt;&lt;br /&gt;At my old job, which also involved multiple processes talking to each other over the network, I created my own logging system, though I'm not sure I called it that.  Really it was an evolution of printf debugging, with a way to control how much output there was.  I had DEBUG macros, controlled by a buglevel variable, which more precisely was a verbosity level.  0 meant nothing, 1 meant a small amount of high level output like entering functions, 4 printed from inside nested loops.  I don't remember what 2 and 3 were, and it was more ad hoc than formally designed, but it seems reasonable that 2 would be top level statements after the initial entry statement, while 3 would from within loops.  E.g.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
int some_function(type param) {
  DEBUG(1, "Entering some_function");
  do sometthing
  DEBUG(2, "I got something %s", something);
  while(condition( {
    DEBUG(3, "loop variables");
    for (some other condition) {
      DEBUG(4, "really verbose");
    ...
}
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What about INFO, ERROR, etc. levels?  I'm guessing those were just printfs -- I had no concept that you'd ever not want to see such output, nor did I have anything like the Python logging flexibility where you can send logging to multiple outputs.  So my homegrown macros were entirely for levels of DEBUG output, and really provided a trace record with varying levels of resolution (and performance hit[1].)&lt;br /&gt;&lt;br /&gt;And I feel weird because what's become common, in Python and Apache and such, is just a single level of DEBUG.&lt;br /&gt;&lt;br /&gt;I've already tried to address that; our logging module contains some custom methods and levels.  HITRACE for my old DEBUG 1, function entry (and sometimes exit).  And TRACE for "even more verbose than DEBUG", but I hadn't pinned down that that meant; now it seems like I'd have to add one more level to really match up to my old system.  And then teach other people how to use it.  Feh...&lt;br /&gt;&lt;br /&gt;I've also wondered if there's a useful distinction between "statements for tracing in general" and "statements for debugging this problem in particular."&lt;br /&gt;&lt;br /&gt;Then of course there's exactly how to split WARNING, ERROR, and CRITICAL, and how to report user errors.  Currently I mostly use ERROR for "there's a problem with our code" and CRITICAL for "there's a problem with the environment" like disk full or network connection failure.  ERROR gets programmers out of bed, CRITICAL gets Ops out of bed.  FATAL is CRITICAL plus a built-in "we die right now."  WARNING is "I'm not sure if this is a problem" or "a human should look at this soon".  Errors because of bad *user* input, I'm not sure, maybe just DEBUG?  Don't want bad users filling up production logs.&lt;br /&gt;&lt;br /&gt;[1] Once Ops came to me and said "the new release is really slow!"  It turned they'd pushed the code to production with a configured buglevel=4, not 1 or 0 as I instructed.  (The macro was such that all that code could have been compiled away, too, but we never bothered; I think we also liked the idea that we could get more output if we needed to.)&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=495172" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:490829</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/490829.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=490829"/>
    <title>refactoring $*#&amp;*# Python</title>
    <published>2018-03-23T02:04:09Z</published>
    <updated>2018-03-23T02:04:09Z</updated>
    <category term="python"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Once again, into the Pyth circle of hell.  This time trying to convert our code from Python 2 to 3.  2to3 does much fo the grunt work of print() and 'from . import', though it didn't always get the latter right.  But instead of string and unicode, we now have string and bytes value types, and a strong barrier between them.  And of course no static compiler to find up front when types might be mixed up.  And yes, we're weak on unit tests, especially tests that exercise all possible code paths.  Things seem to mostly work now, but will they under all conditions?  Who knows?&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=490829" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:485363</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/485363.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=485363"/>
    <title>joining the Rust cult</title>
    <published>2017-10-12T20:06:19Z</published>
    <updated>2017-10-14T17:38:08Z</updated>
    <category term="programming"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">So, programming languages.  Years ago I'd run across D, aiming to be a better C++, or even a better Python -- enabling high level coding without giving up type safety or speed.  It had lots of features, including contracts from Eiffel, and being functional friendly; overall it seemed like a language I'd design.  It was cool, but I didn't code actively enough to bother learning it.  &lt;br /&gt;&lt;br /&gt;Last weekend I did start, but also started on the new cult kid, Rust.  I went in parallel a bit, but Rust has pulled ahead.&lt;br /&gt;&lt;br /&gt;D is not very exciting or revolutionary; it's like a better done kitchen sink.  There's a lot of value in that, and in what it's trying to be, and AFAICT the language itself is pretty good. I've seen people criticize the toolchain, and uptake has been rather modest -- though the forums do see daily activity, at least.&lt;br /&gt;&lt;br /&gt;Rust, OTOH, is trying to be revolutionary: compiler-enforced memory safety, meaning not just no memory leaks but "fearless concurrency", where the compiler would enforce no data races in multithread code unless you did something specifically unsafe.  "No leaks" doesn't sound exciting unless you're an engineer who's had to worry about them; "safe concurrency" is potentially sexy to lots of people.&lt;br /&gt;&lt;br /&gt;On diving in, I noticed something else sexy to me: it's like the unholy love child of C and ML and other functional languages; one blog post even called it a functional language in C clothing.  Enums/sum types/algebraic data types/tagged unions, which I quickly fell in love with while playing with Ocaml; 'traits' or type classes a la Haskell, which serve for generics, dynanmic dispatch, and overloading, all with one coherent mechanism; hygienic macros a la Scheme, something I thought I'd never get to play with seriously unless I got into Clojure.  Also, supposedly, an easy and powerful package system, and a minor taste of mine, nested comments.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=485363" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:474874</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/474874.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=474874"/>
    <title>aliasing fi</title>
    <published>2017-05-13T11:21:04Z</published>
    <updated>2017-05-13T11:21:04Z</updated>
    <category term="computer"/>
    <category term="zsh"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">I think I mentioned not long ago that I found I'd been aliasing fi=finger which breaks if loops in my shell, and marveled that it took so long to find that.  It makes more sense to me now.&lt;br /&gt;&lt;br /&gt;1) Yeah, I didn't script much.&lt;br /&gt;2) When I did do an ad hoc script at the prompt, it was a for loop.&lt;br /&gt;3) Scripts you get are mostly bash scripts.&lt;br /&gt;4) Even an explicitly written zsh script wouldn't have a problem: my aliases are loaded by .zshrc, which is loaded by interactive shells, i.e. not script shells[1].&lt;br /&gt;5) Only when I tried pasting an if loop into a *function*, also loaded by .zshrc after my aliases, did a problem occur.  Possibly it had occurred before and I simply gave up on some unnecessary function that mysteriously didn't work.&lt;br /&gt;&lt;br /&gt;[1] This also sheds light on past failures to ssh in somewhere and invoke a function directly: not an interactive shell, so no functions loaded.  When I try 'ssh ... "zsh -i script_invoking_function"', it works.  So if I want remote function invocation, I'll need to use -i or to load functions outside of .zshrc.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=474874" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:474555</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/474555.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=474555"/>
    <title>why zsh?</title>
    <published>2017-05-12T01:45:46Z</published>
    <updated>2017-05-13T11:21:42Z</updated>
    <category term="computer"/>
    <category term="zsh"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">When I got to Caltech and discovered Unix, the default shell on the cluster was csh, with more user features than the sh at the time, but not a lot.  If you got the lowdown, you could switch to the far more useful tcsh, but the sysadmin refused to make that the default for resource reasons.  There was also ksh, but I never heard people talking about it.&lt;br /&gt;&lt;br /&gt;A few years later zsh came along, and the more techie undergraduate cluster largely switched to it en masse.  It was even made the default shell there.&lt;br /&gt;&lt;br /&gt;Out in the greater world, and in the era of Linux, bash seems the default shell, pretty much incorporating much of what was good about tcsh and ksh, and also displacing any more primitive sh.  zsh still is an exotic thing even Linux people may not have heard of... which is a shame, because it's so much better.&lt;br /&gt;&lt;br /&gt;Granted, it's also way more complicated, and a lot of its cooler features have to be turned on.  If you want a shell that's full-featured out of the box, there's the even more obscure 'fish'.&lt;br /&gt;&lt;br /&gt;And bash can approach, though not catch up to zsh, with the "bash-completion" package.&lt;br /&gt;&lt;br /&gt;But what's so cool?  Well, tab-completion can be far more powerful, working not just on filenames, but environment or shell variables, command options, man pages, process numbers, and git branches.  It can also go to a menu mode, for scrolling around lots of options.&lt;br /&gt;&lt;br /&gt;(But fish will do the magic of parsing man pages on the fly to display command options. :O )&lt;br /&gt;&lt;br /&gt;It's easy to have your prompt display the exit code of the last command, something I find pretty useful; doing that in bash requires writing your own functions.&lt;br /&gt;&lt;br /&gt;Likewise, you can easily have sophisticated right-hand prompts.&lt;br /&gt;&lt;br /&gt;**/ recursive directory listing, though that is something you can turn on in bash. (shopt -s globstar)&lt;br /&gt;&lt;br /&gt;Even more extended globbing, including excluding patterns, or selecting files based on modification time within a window and other criteria.&lt;br /&gt;&lt;br /&gt;Redirection tricks, some of which reduce the need for tee.  |&amp; pipes stdout and stderr to a program such as less.  &amp;gt;! can clobber files even when you have noclobber on.&lt;br /&gt;&lt;br /&gt;I'd anticipated sticking to bash for scripting, for better standards compliance/portability, but I realized that I'm not writing a package script, just in-house tools.  And zsh scripting has a lot going for it.  Arrays just work, while bash arrays were described Sunday as the worst of any language.  I'm using the mod time glob mentioned above.&lt;br /&gt;&lt;br /&gt;zsh can share history between shells.  I find this useful and annoying -- useful now for storing and reusing commands, but also destroys the individual history of a particular window.  Oh well.  An impressive application was when I found myself reusing history across *machines*, where my home dir was NFS mounted.&lt;br /&gt;&lt;br /&gt;"Named directories" mean I can collapse long pathnames in my prompt, e.g. Main/wsgi-scripts becomes just ~WS&lt;br /&gt;&lt;br /&gt;Probably a lot more, but those come to mind.&lt;br /&gt;&lt;br /&gt;That said, there is one odd lacuna in zsh.  bash has --rc-file, to tell it to read in a custom rc (like bashrc) file after everything else.  zsh... doesn't.  And sometimes I would like to start a shell with a custom additional environment, e.g. from ssh.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=474555" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:469356</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/469356.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=469356"/>
    <title>Sometimes doing things right does help</title>
    <published>2017-04-02T01:52:13Z</published>
    <updated>2017-04-02T01:52:13Z</updated>
    <category term="work"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">The work system has two kinds of debug/logging statements.&lt;br /&gt;&lt;br /&gt;One is a class with the standard methods (trace through critical) which are just print statements that add "DEBUG" or "INFO" as appropriate.  There's not even a hint of output throttling.  But it is a class, and so I can rip its guts out and replace them with calls to Python's logging module, and it works.&lt;br /&gt;&lt;br /&gt;Then there's the 500+ naked print statements, with "ERROR" or such in their constructed output strings.  I can search for them easily -- though I can just search for 'print', I think these are the only uses -- but I don't see any programmatic way of converting them, especially as the logging output formatting needs types (%s, %d) which are totally absent from the existing statements.  (And it's python 2, so they are statements.)&lt;br /&gt;&lt;br /&gt;I see a day of boring editing in my future.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=469356" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:466483</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/466483.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=466483"/>
    <title>I hate whiteboarding</title>
    <published>2017-02-11T12:29:25Z</published>
    <updated>2017-02-11T12:29:25Z</updated>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">(Definition: solving a problem or writing code in an interview, in front of people, under time pressure.  Video/online counts as well.)&lt;br /&gt;&lt;br /&gt;I'm not sure I've gotten much better at this in the past year.  It's one thing if the problem is one I already know and I just have to write code; I think I regurgitate under pressure fairly well.  But if I have to really think about the problem then it feels like my IQ drops 20+ points under stress and being stared at.  And when I come up with one idea for a solution, it's hard to try to think of others that might be better in some sense -- after all, the clock is ticking, and I have to start writing code!  Not to mention the fun of having to write correct code without backup documentation or a compiler -- my memory prioritizes the stuff that's hard to look up, like What You Shouldn't Do, or Where Information Is, over the stuff that's trivial to look up at need.&lt;br /&gt;&lt;br /&gt;As for actually being creative, that goes a lot better when I have time to relax, or step away from the problem and not consciously think about it.    A lot of my best solutions just come to me when doing something else, or musing in bed or the shower, or walking.&lt;br /&gt;&lt;br /&gt;Post prompted by Thursday's experience, where I was asked to construct a relative path between two directories, and I saw it as a tree problem and hared down making C++ trees with nodes and everything.  At the end I asked how I'd done, and was told "well, this works, or would work with a bit more polishing of the code, but there's a simpler way with just lists."  One minute after leaving the building I saw what that would be, and at home it took me 18 minutes to code and debug, which I e-mailed in, but apparently got no credit for that.&lt;br /&gt;&lt;br /&gt;I did better Monday, with some basic linked list questions; that rejection was "you did well and seem a fine technologist, but not commercially experienced enough".  Which is back to the Catch-22 of not being able to get experience because I'm not experienced enough.&lt;br /&gt;&lt;br /&gt;On the flip side, Wednesday had a video interview where I had no idea how I did, but they want me to go to NYC for an onsite next week.  So yay, progress... of course, that'll probably be more whiteboarding.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=466483" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:466385</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/466385.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=466385"/>
    <title>JavaScript quirks</title>
    <published>2017-02-05T17:35:25Z</published>
    <updated>2020-10-23T03:27:27Z</updated>
    <category term="javascript"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">I've started studying JavaScript a bit, as you might guess from recent posts.  It's struck me as a mix of Perl, Python, and crack.  It's got some neat things, especially in comparison to one language or the other.  And it's got lots of... wtf things.&lt;br /&gt;&lt;br /&gt;+: exponentiation operator; nested arrays and objects (dictionaries) (without Perl's references); first class functions and lambdas and closures, including nested functions (unlike Perl); Perl-like push/pop/shift/unshift array operators (but what's the performance?); consistent 'valueOf' and 'toString' methods; JSON; multiple kinds of for loops; Perl style labeled break and continue; some convenient conversions (but see below); nice Date methods.&lt;br /&gt;&lt;br /&gt;-: oh boy.&lt;br /&gt;&lt;br /&gt;* JSON stringifies nested structures nicely, but simple output doesn't: [1, [2,3]] outputs as [1, 2, 3].&lt;br /&gt;* (object1 == object2) is always false, no matter the underlying values. This holds for arrays and Date objects too.  Nothing like Python's structural equality, or even that of STL containers.&lt;br /&gt;** But you can do *inequality* comparison: ([1,2,3] &amp;lt; [2,2,3]) == true.&lt;br /&gt;* strings take negative indices a la Python, but arrays don't.  [2020 edit: what was I thinking?  string.slice can take negative indices, but character access via [] doesn't.  And array.slice also takes negative.]&lt;br /&gt;* there's a typeof operator, but it just says 'object' for arrays.&lt;br /&gt;* "5"+2 == "52" (convert 2 to "2", concatenate), but "5"-2 == 3 (convert "5" to 5, subtract.) And no Python string multiplier like "a"*2 == "aa".&lt;br /&gt;** As Avi noted, it gets even weirder given that the values could be hidden in a variable.  a+2=="52", a-2==3&lt;br /&gt;* [1,2]+[3,4] doesn't concatenate arrays, doesn't add by element, doesn't give a type error, but gives... "1,23,4" (turn arrays into strings, concatenate without delimiter.)&lt;br /&gt;&lt;br /&gt;My friend Mark linked me to &lt;a href="https://www.destroyallsoftware.com/talks/wat"&gt;https://www.destroyallsoftware.com/talks/wat&lt;/a&gt; which gives some more:&lt;br /&gt;* []+{} == [object Object]&lt;br /&gt;Ok, addition is commutative, right?&lt;br /&gt;{}+[] == 0&lt;br /&gt;And for luck: {}+{} == NaN&lt;br /&gt;As above, []+[] == ""&lt;br /&gt;** Actually, on playing with typeof, I think those are actually all strings.  "[object Object]", "0", "NaN".  OTOH, {}+[4]+5 == 9 (but typeof string)&lt;br /&gt;** &lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; 5+{}+[4]                                                        &lt;br /&gt;5[object Object]4  // because of course it does&lt;br /&gt;* &lt;br /&gt;&lt;pre&gt;
return
  x;
&lt;/pre&gt;&lt;br /&gt;turns into&lt;br /&gt;&lt;pre&gt;
 return;
 x;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;* All numbers are 64-bit floats; you can still bitshift them, but as integers, so 5.2 &amp;lt;&amp;lt; 2 == 20.  This makes more sense when I remembered that floats are weird, not integers+fractions, so a simple bitshift of the fraction wouldn't make sense.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=466385" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:465980</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/465980.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=465980"/>
    <title>Hoisting Shadows</title>
    <published>2017-02-05T16:49:15Z</published>
    <updated>2017-02-05T16:49:15Z</updated>
    <category term="programming"/>
    <category term="javascript"/>
    <category term="python"/>
    <category term="perl"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">A bit after writing &lt;a href="https://mindstalk.dreamwidth.org/465845.html"&gt;the previous post on shadowing variables in JavaScript&lt;/a&gt;, I came across &lt;a href="http://www.w3schools.com/js/js_hoisting.asp"&gt;this page on hoisting&lt;/a&gt;.  JavaScript re-writes your code so that declarations but not initializations to the top of current scope, meaning the script or function[1].  So&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
console.log(a);
var a=5;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;turns into&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
var a;
console.log(a);
a=5;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Put that way, it's clear why the problem happens, if not why the language was designed this way.&lt;br /&gt;&lt;br /&gt;Does the same thing happen in Python?  Searching did not get clear results.  I saw pages contrasting JavaScript with Python, which doesn't even *have* declarations.  OTOH, the same behavior occurs.  So... I dunno.&lt;br /&gt;&lt;br /&gt;[1] JavaScipt does not have block scoping the way C and Perl[2] do; scopes are delimited by curly braces, but random curly braces do nothing to isolate variables.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
{ a=5; }
console.log(a);
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;will work just fine. :(&lt;br /&gt;&lt;br /&gt;[2] As I was verifying this in Perl, I ran into behavior I'd forgotten.  I'd thrown in "use strict;" but wasn't getting the errors I expected.  Eventually I recalled that $a and $b have special meaning in Perl (I think for comparison functions), and I guess are pre-declared, and I was using $a a la the above code, so strict didn't complain about trying to access $a before assigning to it.  Sigh.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=465980" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:465845</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/465845.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=465845"/>
    <title>Shadows of JavaScript</title>
    <published>2017-02-02T18:43:58Z</published>
    <updated>2017-02-02T18:43:58Z</updated>
    <category term="javascript"/>
    <category term="programming"/>
    <category term="ocaml"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Months ago, Robbie had found this scoping problem in Python, which I &lt;a href="http://mindstalk.dreamwidth.org/450941.html"&gt;reduced to essentials&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I've started finally learning JavaScript, and it has nicer lambdas than Python, and proper hiding of nested functions unlike Perl.  But it has the same scope problem:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
g1 = 12;
function func() {
  document.getElementById("demo").innerHTML = g1;

  var g1 = 5;

}
func();
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(I'm not including the HTML framework because DW/LJ would yell at me if I did.)&lt;br /&gt;&lt;br /&gt;Output is 'undefined', rather than 12.  As in Python, the local variable further down shadows the outer scope variable (doesn't matter if the "g1=12" has a 'var' before it) even for lines before the local variable.&lt;br /&gt;&lt;br /&gt;As mentioned before, Perl has proper lexical scoping here (though not for nested functions.)  I don't think I can even create similar code in Scheme/Lisp, where the scoping is explicit with parentheses.  (There's 'define' but I think that makes a new global, and it didn't work.)  In Ocaml I have&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
let g1="10";;

let func () =
  print_endline g1;
  let g1="cat" in
    g1
  ;;

func();;
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Which I suspect is as explicit as Lisp parentheses, in its own way; the print line is obviously outside the following "let ... in...".&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=465845" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:465263</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/465263.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=465263"/>
    <title>fast array rotation</title>
    <published>2017-01-28T18:27:15Z</published>
    <updated>2020-07-14T05:54:53Z</updated>
    <category term="math"/>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>3</dw:reply-count>
    <content type="html">A simple problem I'd never had occasion to think much before, before I saw a sample coding problem.&lt;br /&gt;&lt;br /&gt;How to rotate the elements of an N-element array by k spaces?  An obvious way is to shuffle it one space, k times, but that's slow, O(N*k).  Faster, which I saw about as soon as I thought about performance, is to use a second array B, where B[(i+k)%N] = A[i].  But that takes O(N) extra space.  Can you do better?&lt;br /&gt;&lt;br /&gt;Yes, as I realized at 5am.  For each element A[i], move it to A[(i+k)%N].  O(N) time, O(1) extra space.  Can't beat that!&lt;br /&gt;&lt;br /&gt;Except some mildly tricky math intervenes: the natural approach only works if N and k are relatively prime.  A more general solution is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
let g = gcd(N,k)
for i in [0,g)
  for j in [0, N/g)
    shuffle element k spaces
&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Despite looking like a double loop, it's still O(N), with g*N/g iterations.&lt;br /&gt;&lt;br /&gt;[2020 Edit: Looking back... I find this less than clear.  I went to the code to make sure I got it right.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;
#ar = (array)
g = gcd(N, k)
for i in range(g):
    cur = ar[i]
    for j in range(1, N//g+1):
        temp = ar[(i + j*k) % N]
        ar[(i + j*k) % N] = cur
        cur = temp
&lt;/pre&gt;&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;I've also learned that C++ has a gcd function now.  std::experimental::gcd, in the header experimental/numeric.  C++17 moves it out of experimental but even g++ isn't doing that by default.&lt;br /&gt;&lt;br /&gt;The really annoying this is that this is the sort of solution that comes naturally to me lying in bed, with little conscious effort, but that I'd likely fail to get in a whiteboard session or timed coding test, due to stress dropping my working IQ.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=465263" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2009-05-20:374172:464671</id>
    <link rel="alternate" type="text/html" href="https://mindstalk.dreamwidth.org/464671.html"/>
    <link rel="self" type="text/xml" href="https://mindstalk.dreamwidth.org/data/atom/?itemid=464671"/>
    <title>Applying A*</title>
    <published>2017-01-17T18:08:38Z</published>
    <updated>2017-01-17T18:08:38Z</updated>
    <category term="programming"/>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">I've played a lot of freeciv and freecol over recent years.  Both games let you order a unit to go to some square, and hopefully it takes the fastest route there.  The 'world' is a square grid, of various terrain types and associated movement costs -- e.g. plains or desert take 1 move, but mountains take 3; roads and rivers take 1/3 no matter what terrain type they're laid over.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://en.wikipedia.org/wiki/A*_search_algorithm"&gt;A*&lt;/a&gt; is this sweet magic algorithm for finding shortest paths in some graphs efficiently, vs. doing breadth-first search in all directions, but I was having trouble applying it mentally.  I was using the common Manhattan distance heuristic, h((0,0),(x,y)) = x+y, and I wasn't getting good results: the algorithm would cheerfully march down a straight plains path to the goal, while ignoring a path that might step away and into mountains, but then ride a river to the goal much faster.&lt;br /&gt;&lt;br /&gt;So I backed off, and thought about BFS.  I realized that would work better if instead of naive BFS, enqueuing grid squares as you found them, instead you ranked them by total travel time so far.  This is basically A* without a heuristic.  Instead of exploring all paths N squares away, you'd explore all paths N moves away; it would still be radiating in all sorts of directions, but at least you'd find the shortest path to the goal.&lt;br /&gt;&lt;br /&gt;Then I realized I'd been using the wrong heuristic; the right one should be the shortest possible journey.  Or as WP says, "it never overestimates the actual cost to get to the nearest goal node."  So the heuristic in this application has to consider rivers and roads, such that h() = (x+y)/3, not (x+y).  This works much better: the plains march looks less attractive as it advances, converting cheap heuristic moves into actual plains moves, and the "mountain and away" move gets a chance to be considered.&lt;br /&gt;&lt;br /&gt;Actually, units and roads can go diagonally, though rivers are rectilinear, so the proper heuristic is h((0,0),(x,y)) = max(x,y)/3.&lt;br /&gt;&lt;br /&gt;Actually actually, infantry units only have one move, but are still guaranteed one square of movement per turn, so can march across mountains as easily as across plains; it's mounted units, with e.g. 4 move in freecol, that really care about base terrain type.  Also fractional movement can be useful, e.g. I think a unit with 2/3 move left (after moving on river) can still move onto an adjacent plains.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=mindstalk&amp;ditemid=464671" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
