Sunday, March 01, 2015
My, the days seem to fly right on by
You may have noticed that I've been blogging rather frequently over the past few months. In fact, I've been trying to blog at least one entry per day this year and I've been pretty good at maintaining that level. But I must apologize for missing February 29th and 30th—those days just slip right by me for some reason.
Ah well …
Monday, March 02, 2015
Hey! You can actually make out the lyrics in this version
[Music is playing]
♫With the lights out, it's less dangerous
Here we are now, entertain us
I feel stupid and contagious
Here we are now, entertain us …♫
“Who is that?”
“Guess.”
“Um … Frank Sinatra?”
“Nope.”
♫I'm worse at what I do best
And for this gift I feel blessed
Our little group has always been
And always will until the end
Hello, hello, hello, hello … ♫
“It's a cover version of a Nirvana song.”
“I don't think it's Tony Bennett ‥ ”
“Nope.”
“Then who?”
“Paul Anka.”
“Huh. The album is ‘Rock Swings.’ I might have to get that …”
Tuesday, March 03, 2015
Hurry up and wait
One thing about testing a regression test is that there's quite a bit of “hurry up and wait”—I add a check, run the test and wait. Then investigate the output and either make a note of a potential problem (either in the configuration of the test data or a possible bug in one of a number of components) or adjust the check (“hmmm … on second thought, it should really be this”) and rerun the test.
Fortunately, the regression test for “Project: Sippy-Cup” (runs for maybe half an hour) isn't as long as the regression test for “Project: Wolowizard” (about 4½ hours).
Seriously, if you care about your data, keep it close!
We assume everything we publish online will be preserved. But websites that pay for writing are businesses. They get sold, forgotten and broken. Eventually, someone flips the switch and pulls it all down. Hosting charges are eliminated, and domain names slip quietly back into the pool. What’s left behind once the cache clears? As I found with that pitch at the end of 2014, my writing resume is now oddly incomplete and unverifiable. Ex- editors can provide references, but I have surprisingly few examples of published work to show beyond scanned print features from my early days, so I’ve started backing up my work.
For media companies deleting their sites, legacy doesn’t matter; the work carries no intrinsic value if there is no business remaining to capitalize on it. I asked if RCRD LBL still existed on a server somewhere. It apparently does; I was invited to purchase it for next to nothing. I could pay for the hosting, flip the switch on, and all my work would return. But I’d never really look at it. Then, eventually, I would stop paying the bills, too.
Via Lobsters, All My Blogs Are Dead - The Awl
I hate to keep harping on this, but really, you can't even trust companies to archive their own website where they paid for their content!
It's also sad that Carter Maness didn't even feel it was worth the money to save his own work, which sadly, is another example of someone not caring to manage their own computer (in this case, a server with articles that prove he he was paid to write and thus, can include on his résumé).
Wednesday, March 04, 2015
Mimicking C APIs in Lua
Last Sunday, the latest announcement of luaposix lead me to state the following observation on the Lua mailing list:
- From
- Sean Conner <sean@conman.org>
- To
- Lua mailing list <lua-l@lists.lua.org>
- Subject
- Literal mimicking of C APIs in Lua (split from Re: [ANN] luaposix 33.3.0 released)
- Date
- Sat, 28 Feb 2015 23:16:51 -0500
This isn't about luaposix per se, but this is prompting this observation about Lua wrappers for C APIs: they tend to mimic it quite literally (to the point where I think I've said this before: if I wanted to code in C, I know where to find it).
I checked, and sure enough, the Lua wrapper around syslog()
was
what I expected (and had found in several other syslog()
wrappers for Lua)—a very thin wrapper over
syslog()
leading to this in Lua:
syslog.syslog(syslog.LOG_WARNING,string.format("foobar %d is at %d capacity",fooid,foocap))
I seem to be the only one who make it easy to use
syslog()
in Lua:
syslog('warning',"foobar %d is at %d capcaity",fooid,foocap)
I went to the trouble of ma
king the module itself callable (but you can still call
syslog.log()
if you want) and handle the call to
string.format()
be
half of the caller because in 90% of the cases I call
syslog()
, I need formatted output.
It just struck me as odd that not many writers of C-based Lua modules bother to make it easy to use their modules and I was about the thought process behind it (or the lack of thought process). The best answer came from Gary Vaughan, author of luaposix:
- From
- "Gary V. Vaughan" <XXXXXXXXXXXXXXX>
- To
- Lua mailing list <lua-l@lists.lua.org>
- Subject
- Re: Literal mimicking of C APIs in Lua (split from Re: [ANN] luaposix 33.3.0 released)
- Date
- Sun, 1 Mar 2015 09:02:00 +0000
It's precisely because I don't want to code in C either that the low- level API of luaposix aspires to be as thin a wrapper for the C API as possible. It's easier, faster and less error-prone to write the Luaish API on top of the thin C wrappers in Lua than it is to write the fancy stuff in C.
Not only that, this leaves the door open to replace the C bindings with an FFI binding that the Luaish layer can equally sit on top of and ultimately shipping no C code at all in luaposix… as long as a dependency on LuaJIT and/or LuaFFI is an acceptable compromise. When the low-level C code implements the user- facing API, all of this is a lot more difficult.
He's got a good point—make the C layer as thin as possible:
static int syslog_syslog(lua_State *L) { syslog(luaL_checkinteger(L,1),"%s",luaL_checkstring(L,2)); return 0; }
and leave the fancy stuff up to Lua:
local m_priority = { emerg = 0, emergency = 0, alert = 1, crit = 2, critical = 2, err = 3, error = 3, warn = 4, warning = 4, notice = 5, info = 6, information = 6, debug = 7 } function syslog(priority,...) syslogcore.syslog(m_priority[priority],string.format(...)) end
But there is a flaw when he metions LuaJIT (and LuaFFI in general):
C declarations are not passed through a C pre-processor, yet. No pre- processor tokens are allowed, except for
#pragma pack
. Replace#define
in existing C header files withenum
,static const
ortypedef
and/or pass the files through an external C pre-processor (once). Be careful not to include unneeded or redundant declarations from unrelated header files.
In the case of syslog()
, it's not that big an issue—the
levels are standardized so it's easy
to supply the proper values, but it's different for a function like
socket()
. A thin C wrapper is trivial:
static int socket_socket(lua_State *L) { lua_pushinteger( L, socket( luaL_checkinteger(L,1), luaL_checkinteger(L,2), luaL_checkinteger(L,3) ) ); lua_pushinteger(L,errno); return 2; }
Not so easy is defining the values for those three parameters. The first is an arbitrary number defining the “family” the socket belongs to, ether IP, IPv6, Unix domain, etc. The second parameter further defines the socket type, whether it's a stream based socket, or you want actual packets. The last parameter can, in 99% of the cases, be 0, so we shall ignore it. In C, it's typically called like:
s = socket(AF_INET,SOCK_STREAM,0);
But the actual value of AF_INET
may vary from operating
system to operating system (they do—I checked a few systems to make sure) so
it's not always as straightforward to skip C entirely when wrapping a C API with LuaJIT.
Overall though, the idea is sound and I do find it intriguing, but not enough to stop the approach I've been taking.
Mind blown
When you bite into a Thin Mint, you probably aren't wondering where it comes from. (The Girl Scouts, of course.) But wait, there are two bakers. And they make two very different Thin Mints: One is crunchier, more minty. The other is richer with a smooth chocolate coating.
Via Jeff Cuscutis at FaceGoogleMyBookPlusSpace, 6 Girl Scout cookies you thought you were getting but aren't - Los Angeles Times
Wait … what?
Thursday, March 05, 2015
Notes about an overheard phone conversation about an upcoming election
Ring.
Ring.
“Hello?”
“Yes, this just a short survey and should only take a moment of your time.”
“Okay … ”
“If the election were held today, who would you vote for, Frank Chapman, Jeremy Rodgers or Jamie Sauer?”
“Right now? Bozo the Clown.”
“Um … shall I put you down for ‘undecided’ then?”
Friday, March 06, 2015
So, why exactly are churches tax exempt?
A government crackdown on churches has Christians in Lake Worth, Fla., wondering if they live in the United States or the former Soviet Union.
Churches in Lake Worth, population 36,000, have been ordered to acquire a business license. As if the church has to get the government’s permission to preach and pray?
But wait. It gets worse, folks.
City officials were so concerned about one congregation that they dispatched a code enforcement officer cloaked in a hoodie to spy on a Southern Baptist church that was meeting in a coffee house.
Florida city wages soviet-style crackdown on churches | Fox News
Bunny had sent me the link, and when we went out to lunch, we had a very lively discussion about this article.
An interesting portion is this quote from the above article:
“After we opened up the coffee bar and started doing services, I heard that he told people we were anti-gay,” Olive said. “So I went to his shop to ask him about that.”
Florida city wages soviet-style crackdown on churches | Fox News
But in looking up other articles about this, I came across this:
Olive told the Tribune he had heard that City Commissioner Andy Amoroso, who owns a newsstand and gay-pornography shop in Lake Worth, was telling people Olive and his church were “anti-gay,” a charge Olive denied and attempted to address personally with Amoroso.
U.S. city spies on churches, demands licenses
which Bunny felt explained the quote in the first story. It also clarified that the Common Ground Chuch also runs the Common Grounds Coffee Bar. And it was made clear in the second article that the Common Grounds Coffee Bar also rents the space out to other groups and organizations. But what, exactly, is going on here?
After lunch, I decided to do a bit more checking on this story, as I think it's a facinating story. It's fun reading about this story from other points of view, say, from this alternative leftist website:
The city does not require churches or nonprofit organizations to pay a business license tax, but they are required to obtain a use and occupancy certificate – which officials use to ensure they don’t pose public safety hazards or break any local, state, or federal laws.
…
The code officer, Gerald Coscia, found the church may have been overcrowded and possibly lacked a sufficient emergency exit, and he said the building likely failed to comply with the Americans With Disabilities Act.
He determined that Olive’s landlord, Mission Education International, had a valid business license for the coffee shop with an exemption for charitable organizations, but the church lacked a use and occupancy certificate.
City officials notified the landlord by letter and outlined what they needed from the church to issue the proper permit, but Olive claims the investigation violates “the separation of church and state.”
Whatever the truth, it's clear that Lake Worth really stepped on a hornet's nest.
Because a wooden reindeer just wasn't enough
Several weeks ago Bunny bought several planks of nice wood for some projects, among them this plank of white oak:
She cut off about an 8″ section off one end because of a hairline crack in the wood, and it was this chunk of wood that, as odd as it may seem, “spoke” to me. I thought I could make a neat little box with that chunk of wood. So after work, I spent about three hours in the garage playing around with the power tools. [Have fun, just be careful not to cut your fingers off! —Bunny] [I won't cut my fingers off. —Sean]
First job, slicing off thin pieces of wood to form the top, botton and sides. The wood was too tall for the bandsaw, so I had to resort to using the table saw for slicing the wood. I used a scrap piece of wood to measure the kerf of the blade (eighth of an inch—wow!), and taking the width of the wood into account (1¼″) I figured I could get about four slices, each about 3/8″ wide. Usually when using the table saw for this type of cut, you raise the blade as high as it can go, make one pass, flip the piece over and cut a second pass, thus cutting a slice off. But I couldn't raise the blade high enough—two passes wouldn't be enough. I ended up having to make four passes, cut, flip 180° along the cut for cut two, turn 90° for cut three, then another 180° flip for the final cut. That left about an inch square in the middle, which required the use of a ryōba, a very thin and very deadly double-sided saw from Japan.
While cutting the first slab, I made a mistake when flipping the board over (180° perpendicular to the cut), which meant I wasn't getting the four slices I had intended. I ended up with three 3/8″ pieces, and one seriously mangled fourth piece that ended up in the scrap pile. Sigh.
My original intent was to cut two of the slabs in half for the sides, making the box about 4″ tall, but because of the mistake I was forced to make the box thinner. No big deal, as this is a learning experience. I took one of the three pieces, made some measurements, took the kerf into account, and cut the four sides.
Now … how to join them?
The cut boards are 3/8″ thick, that's pretty thin actually, and I was concerned that my original idea, a miter joint, just wasn't going to work. I then thought that maybe finger joints would work, and I started to experiment with some scrap pieces of wood. [You'll shoot your eye out! —Bunny] [I'm working with a table saw, not a Red Ryder Carbine Action 200-shot Range Model air rifle with a compass in the stock and thing which tells time. —Sean] [Well then … you'll cut your fingers off! —Bunny] That wasn't going to work.
It looked like simple butt joints were the way to go.
This was when I realized my next mistake. I had cut across the hairline crack in the wood when making the sides; by now two of the sides had snapped along the crack, leaving me with two short sides. I was bound and determined to just use the slab of wood I started with, so another change in plans—making not a square box but a rectangular box. I could take into account Bunny's concerns over the crack in the top and bottom of the box by just cutting it off; it meant I would lose two inches in one dimension.
I then decided, what the heck, let's make it a 6″×6″ box.
It's not like I'm following any set plans here.
Next step—sanding. The belt sander would make short work of this, but there was an issue—
The board was so thin, the belt sander was forcing the wood down into this gap between the work surface and the sanding belt. The solution: a sacrificial board to “mind the gap” as it were.
Which was then followed up by some “hand” sanding:
One last step for the day— gluing up the sides of the box. Bunny has a ratcheting strap clamp. It's a strap with four plastic “corners” (think a hocky puck with a quarter slice cut out). You place the corners of the box in the four “corner” pieces, then tighten the strap down with the ratchet. Unfortunately, my box was just too small for this to work. The ratchet requires a miminum amount of space, and 6″ wasn't enough since the ratchet sits inline with the strap (although, now that I've found a picture of it in use, I think I wasn't using it correctly; I've just checked, and yes, I could have used it. Maybe. It was a very tight fit).
Okay, I needed to ensure the sides were square. There's the table saw fence. I could use that to square off one side. I could then use the miter gauge to ensure a right angle to the fence. Add in some clamps and …
Hey, it gets the job done.
I'm leaving the glue to dry overnight and tomorrow I'll glue on the top and the bottom, cut the lid, add some finish to the outside and felt the inside and then I'm done.
Saturday, March 07, 2015
I shouldn't give up my day job
I had the four sides of the box formed.
It was now time to glue the top and bottom onto the sides. Wax paper to prevent the box being glued to the work surface. Clamps to apply the appropriate amount of pressure while the glue sets.
Three hours later, and I have a box. It's a box that, as of now, can't be opened, but that will be addressed shortly. First, some sanding to even the outside of the box.
Fortunately, I was able to get most of the sanding done on the belt sander before the “belt-o-sand” came flying off. [Flag! Embellishment penalty! It did not “fly off” but rather broke in half and made a horrible flapping noise. —Editor] [Spoil sport! —Sean] The hand sander was used to finish the job, and frankly, it didn't look half bad.
Now, about making a box that can be opened. The approach is to cut the box in half, along the sides. In theory, I'll have a box and a matching lid with little work.
In theory. In practice … well … I'll state right now, that cutting a box “in half” is way easier to say than to actually do. Yes, I did manage to cut it in half:
but sadly, my attempts at doing so where, shall we say, “less than imperfect.”
And every attempt to fix the issues lead to further problems. After reducing the height of the box by nearly half (which was already half my original height, so by now we're talking a quarter of the original height), I decided the best thing to do would be to declare it done, and instead of attempting to add a hinge on one side and a clasp on the other, just have a clasp on each side to hold it together.
Bunny felt I should attempt to fix the issue and finish the box, but I could only see thing getting worse. The box was just tall enough for its intended purpose (a dice-storage and dice-rolling box for the bi-monthly D&D game) and further futzing would be pointless.
Bunny then ask if she could attempt to fix the box. I told her to have fun, but like I was afraid of, in the process of “fixing it” she managed to shorten the height so much that it couldn't store my dice. She's confident that she can fix this problem, by adding some height back to the sides. I'm declaring it a failure and have learned the following from the mistakes I made while building this project.
- Do not attempt to resaw lumber that is too wide for the equipment we have (I've found out that the term I was using, “slicing,” is incorrect, and what I was technically doing is called “resawing”).
- I should resaw wood of sufficient length so I can send it through the planer.
- I should not be afraid of joining several pieces of wood together to form a larger, wider, piece of wood.
- I now know how to use the ratcheting strap clamp.
This was a learning experience, and I'm happy to have attempted something a bit beyond my skill level. And while I failed to actually make a box, I did learn from my mistakes, so it wasn't a total loss.
Sunday, March 08, 2015
The likely cause of addiction
If you had asked me what causes drug addiction at the start, I would have looked at you as if you were an idiot, and said: "Drugs. Duh." It's not difficult to grasp. I thought I had seen it in my own life. We can all explain it. Imagine if you and I and the next twenty people to pass us on the street take a really potent drug for twenty days. There are strong chemical hooks in these drugs, so if we stopped on day twenty-one, our bodies would need the chemical. We would have a ferocious craving. We would be addicted. That's what addiction means.
…
But in the 1970s, a professor of Psychology in Vancouver called Bruce Alexander noticed something odd about this experiment. The rat is put in the cage all alone. It has nothing to do but take the drugs. What would happen, he wondered, if we tried this differently? So Professor Alexander built Rat Park. It is a lush cage where the rats would have colored balls and the best rat-food and tunnels to scamper down and plenty of friends: everything a rat about town could want. What, Alexander wanted to know, will happen then?
In Rat Park, all the rats obviously tried both water bottles, because they didn't know what was in them. But what happened next was startling.
The rats with good lives didn't like the drugged water. They mostly shunned it, consuming less than a quarter of the drugs the isolated rats used. None of them died. While all the rats who were alone and unhappy became heavy users, none of the rats who had a happy environment did.
Via FaceGoogleMyBookPlusSpace, The Likely Cause of Addiction Has Been Discovered, and It Is Not What You Think | Johann Hari
Interesting, and it fits with animals in the wild getting stoned to escape their hellish lives I posted about last month.
Monday, March 09, 2015
An exhaustive list of countries that do not use the Metric System.
There are only three four countries that do not use the metric system.
One of them is a former British colony that parted ways over some taxed tea,
the second country was formed from former nonvoluntary agrarian workers from the former British colony that parted ways over some taxed tea,
and the third …
is surprising.
Update on Tuesday, March 10th, 2015 at 3:07 AM Eastern
My friend Bibo commented on FaceGoogleMyBookPlusSpace, that growing up in the Bahamas, he remembered using the Imperial System and not the metric system. And from some checking (granted, I only checked two sites) it appears they may still use the Imperial System.
I wonder if there are any more countries that don't use the Metric System?
Tuesday, March 10, 2015
For want of a scan my sanity was lost
I want to scan a picture.
There's a combination printer/scanner not six feet away from my computer.
I open the “printer utility” and select “scan.”
“I am sorry,” said the “printer utility.” “But the driver version of your software is older than twenty minutes. Please exit and try upgrading your software, you obsolete bag of water. Have a nice day.”
Fine.
Navigate to the manufacturer's web page, type in the model number on the front of the printer, and get back a list of eight possible printers.
Really? Eight different models of this one particular model? Sigh.
I start examining the printer for a more specific model number. Of course it's on the bottom. In a 6pt font. Printed in dark grey on a medium black background.
Backwards.
Push the dark thoughts away. They won't help.
Select the actual model.
Boggle at the 200MB download for a “printer driver.” Wait several minutes while it downloads. Open the download.
“Do you really really REALLY want to run something you downloaded from the Internet equivalent of an unmarked conversion van in Compton?” asked my computer.
“What choice do I have?” I answered, selecting “No, but you're going to do this anyway, aren't you?” button.
“It's open—are you really really REALLY sure you want to run this from the Internet equivalent of a Mexican pharmacy?”
“What did I tell you?” I answer, selecting the “Okay, but don't say I didn't warn you, sucka!” button.
I am instantly blinded by the hot fuchsia on orange text welcoming me to the latest and greatest version of the “driver.” Unfortunately, before I can hit anything, a message pops up: “I am sorry, but this driver installation is twenty-two minutes old and therefore, completely and utterly obsolete. Please exit and try upgrading your software, you decrepit excuse for a carbon-based life form. Have a wonderful day.”
I re-navigate to the manufacturer's web page, only to be informed,
“You really expect me to serve up this page to that obsolete webbrowser?
It,
like,
hasn't been updated at all today,”
and promply returns a 489 WEB BROWSER OLDER THAN TWENTY MINUTES I'M REFUSING SERVICE
error code.
I fake the user agent string and try again.
“You think faking the user agent is going to work?”
489 WEB BROWSER OLDER THAN TWENTY MINUTES I'M REFUSING SERVICE
error code.
I spend the next hour downloading the latest web browser.
“Thank you. That's better. Now you can download your printer driver.”
“Ahah! Not so fast!” I said, refreshing the page.
“You really expect me to serve up this page to that obsolete webbrowser?
It's,
like,
sixty-two minutes old.”
489 WEB BROWSER OLDER THAN TWENTY MINUTES I'M REFUSING SERVICE
error code.
…
“Ha ha! Just kidding! Here's the latest version of the driver for you to download.”
Twenty minutes later, I open the download.
“Do you really really REALLY want to run something you downloaded from the Internet equivalent of the Red Light District in Shanghai?” asked my computer.
“It's either run this, or I install Windows 8,” I said, hitting the ”Run this, or I install Windows 8” button.
I am instantly blinded by the animated hot fuchsia on nuclear orange text welcoming me to the latest and greatest version of the “driver.”
I spend the next few minutes carefully navigating my way through the installation procedure,
trying to avoid the “value added” software the manufacturer so carefully thoughtlessly maliciously included with the “driver.”
I scan through the “Terms of Service” and am thankful that I do not have, nor do I plan on having, any kids
(Ha!
Thought you could get me on that one,
didn't you?)
It's only on the penultimate step where I see that,
should I attempt to scan a document,
I could use the operating system installed software to scan,
but really,
who would want that?
Really?
I just wasted over an hour when a preinstalled program that comes with the operating system, would work just as well?
Sometimes, I despise modern software.
THIS is still a keyboard
Sigh.
It just really isn't my day.
I came across the USB Typewriter (link via Hacker News) and I was planning on this nice post where I talk about the USB keyboard and this image I took twenty-four years (ouch) ago:
and how I still have the typewriter in question, only to find out I blogged about the USB Typewriter 3½ years ago (via Hacker News no less!).
On the plus side, it appears they're now selling conversion kits, but sadly, my typewriter (a Smith-Corona SkyRiter) is not compatible with the kit.
Sob.
Wednesday, March 11, 2015
The Hipster typewriter is no Hermes 3000
I was reading the comments about the USB Typewriter when I came across this:
The Hemingwrite is a minimalist digital typewriter for distraction free writing composition. It combines the simplicity of a typewriter with modern technology like an electronic paper screen and cloud backups to create the best possible writing experience. It is designed to do one thing only but do it exceptionally well. Since there is no email, Facebook, browser, or menus, you are able to stay in your creative groove and finally get your writing done!
Hemingwrite - Set your thoughts free
My first thought was, my god is that hideous looking. My second thought was, it's a larger TRS-80 Model 100 with a smaller screen, how is that even possible? My third thought was, people really need to be forced not to check GoogleMyFacePlusSpaceBook while they write?
Apparently so, and they're willing to pay for the limitations, oddly enough.
I don't know. I can see the appeal of not being distracted while writing, but personally, I'm more distracted by the ugliness of the design, and the small screen just doesn't appeal to me. But really, how hard is it to just disable the network? Or even take a pair of scissors to the Ethernet cable?
Or even, you know, use a pen?
Thursday, March 12, 2015
How can you be a Hipster if you aren't using a Hermes 3000?
Jeff Cuscutis commented on my post “The Hipster typewriter is no Hermes 3000 (at MyFaceGoogleSpaceBookPlus):
The whole thing is ugly. If you really want the hipster writing experience, get a real portable typewriter. Then you can annoy your fellow coffee shop patrons.
And then he linked to this article about someone who annoyed fellow Intarweb users with his portable typewriter:
I definitely look like someone who is a bit insane. That’s how I thought of it, before I clicked to look at the hundreds of replies; I figured people were probably wondering why I would bring my typewriter to a park. And when I started reading the comments, I saw most people had already decided that I would bring my typewriter to the park because I’m a “XXXXXXX hipster.” Someone with the user handle “S2011” summed up the thoughts of the hive mind in 7 words: “Get the XXXX out of my city.”
Illmatic707 chimed in: I have never wanted to fist fight someone so badly in my entire life.
Leoatneca replied: Bet 90% of his high school did to. It’s because of these guys that bullying is so hard to stop.
I Am An Object Of Internet Ridicule, Ask Me Anything - The Awl
While he may look like a Hipster, he's far from one—for crying out loud he's using a 1979 Royal Safari portable typewriter! No Hipster would be caught dead using that. Now, had he been using a Hermes 3000 …
What's with the Hermes 3000 anyway?
“So, what's with this Hermes 3000 business?” you may ask.
Go ahead. Ask. I'll wait.
And for the answer, you'll have to read the graphic novel The Guy I Almost Was. Don't worry, there's nothing to buy—the entire thing can be read online.
Friday, March 13, 2015
Managing our own data is hard! Let's go shopping!
The sad truth is that the overwhelming majority of people, including highly technical capable people, don’t want peer-to-peer protocols. They don’t want to own their own data. They just want ease. Convenience. Someone else to take over and take care of their data problems …
Via Hacker News, The Internet: We’re Doing It Wrong | TechCrunch
We're to blame.
Not some vast, worldwide conspiracy against general computer use.
Us.
Don't Panic
For those suffering from paraskevidekatriaphobia, DON'T PANIC! It'll all be over in twenty-four hours.
Um … that is, today will be over, not the world.
I hope.
Saturday, March 14, 2015
Today's Daily Announcement
Those of you suffering from paraskevidekatriaphobia can rest easy now that Friday the 13th is over. Unfortunately, those of you suffering from pastrophobia are advised to stay indoors for the next twenty-four hours, and be especially aware of 9:26:53 local time (AM for sure; PM if you don't use a 24-hour clock).
That is all.
Sunday, March 15, 2015
Best stay in bed
Those of you suffering from pastrophobia can rest easy now that π Day is over. But alas, we aren't safe quite yet, for it is the Ides of March.
Be safe. Climb back into bed. And avoid going to the government buildings.
Monday, March 16, 2015
Twenty percent of sick days are taken on Monday
I have some good news for Those of you who have been traumatized for the past three days—they're over.
The bad news—it's Monday.
What are some things that programmers and computer scientists know, but most people don't
Something I have to try to explain time & again when a non-technical person asks me “how do I do x on my computer” is that I don't know. I can't explain to you step by step over the phone how to make an image bigger in your document or how to print on both sides of the paper or how to switch between the internal and external speakers. I can probably – given the computer in front of me, some opportunity to explore the problem and accurate information about what you're trying to do – figure it out. I'm familiar with the language of user interfaces and can use intuition and experience to explore an unfamiliar tool. I'm also less afraid of accidentally breaking something.
Via Dan Lyke on FaceGoogleMyBookPlusSpace, What are some things that programmers and computer scientists know, but most people don't? - Quora
This is something that took me a long time to impart to my Dad—that just because I program computers doesn't mean I can solve all his computer problems. Especially the Microsoft Windows problems he has from time to time, as the last time I used Windows, it was actually called MS-DOS.
There is a lot of wisdom and truths on that page. I'm finding myself nodding and agreeing with pretty much everything on that page.
Tuesday, March 17, 2015
When will the parade of horrible days end?
You Irish ophidiophobics should be okay today, but those of you suffering from hagiophobia, chlorophobia, or methyphobia might want to stay in bed for the next twenty-four hours or so.
It has been rough the past few days, hasn't it?
Wednesday, March 18, 2015
“Computer on and ready?” “Check.” “Coke?” “Check.” “16″ rotary debugger?” “Pepperoni, check.”
Three years ago, as I was working on the regression test for “Project: Wolowizard,” I decided it might be a good idea to make a checklist of the steps required to run the thing, because it's complicated. It's broken into four sections:
- Steps to ensure you have the proper credentials to obtain the programs from the build server and install them on the testing servers (this needs to be done only once)—35 steps.
- Steps required to prepare the testing system to run a regression test—51 steps, of which, 3 are optional.
- Steps required to run the regression test—25 steps.
- Steps to take after the regression test has finished—15 steps.
As you can see, it's not a short list but that's because I attempted to make it as explicit as possible (and while it could be automated, the time it would take to automate would exceed the time saved).
I say “as possible” because there's implicit knowledge I have about the environment and forget to include, like “Oh yeah, I assumed that NFS would be working” and “that's right, we have a new build server and ‘Project: Wolowizard’ has yet to be set up on that” and “oooh, yeah, you need to talk to R before you run the regression test as the system might not be available for testing.”
This is coming up because fellow cow-orker T has been tasked with running the “Project: Wolowizard” regression test (as I've been busy getting the “Project: Sippy-Cup” regression test working) and these issues are coming up as he works his way through running the test.
Thursday, March 19, 2015
Overheard conversation from a garage turned into a woodworking shop
VRRRRRRROOOOOOOOOOOOOOMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
(Over the noise of a vacuum cleaner) BRRRZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
(Sounds continue for a few seconds, then over both the following is heard)
“Ow! XXXXXXXXXXXXX XXX of a XXXXX XXXXXXX that hurt! XXXX!”
(From inside the house) “Did you say something, dear?”
[No one was seriously hurt in the making of this post, but do read this followup. —Editor]
Don't call me Knuckles McStubbyfingers
Despite the impression the previous post might have given, the injury I sustained isn't life threatening, there was no blood spraying all over the garage, and I still have all my fingers and eyes. Heck, my clothes didn't even get bloody. It just hurt.
So, with that said …
I decided to attempt another wooden box. After work today, I found another piece of wood—this time a nice plank of ash.
It's not as wide as the last piece, so only two passes with the table saw are required to resaw this into some thinner wood.
The wood got a bit burned while cutting on the second pass through the table saw, but a few trips through the planer and all is good.
I then glued them up:
And a few hours later I had a nice thin plank from which to make my box.
The resulting board was 11″ by 19″. From this, I need a top, bottom and four sides. Since I want the resulting box, when open, to lay flat, both halves need to be the same height, so I need enough height on the box to form two halves. And instead of trying to form a box and then cut it, I wanted to cut the sides now, so I really need eight sides. I figured that the top and bottom could be 7″×7″, leaving me with enough material to make eight 7″×1″ sides.
The top and bottom pieces were easy to cut.
It was the sides that proved to be rather painful.
Now, on some previous images, you may have noticed the surface of the table saw had a wood inset around the blade. The table originally came with a red plastic piece that fits there, but Bunny's brother, when he was here helping Bunny set up the saw, said that it wasn't worth using and that she could get better results with a custom wood inset, which he made himself and trued up perfectly. Unfortunately, over time, the wood apparently shrank a little, and said insert was no longer quite flush with the surface. Not much, just a hair, but it was enough that when I was cutting a side, the piece got caught right at the far end of the inset. I lifted the Micro Jig, probably too much, as I tried to negotiate the wood across the inset when Newton's Third Law of Motion kicked in. The spinning blade o'death caught the piece and accelerated it to warp 7, shooting it into my right side.
I think it says something when I was more upset over ruining the piece of wood than I was of nearly having my eye shot out.
All wasn't lost though—I was able to salvage what I had left and got all the pieces cut.
Last thing for the day—a bit of gluing:
It's one-half of the sides of the box. Tomorrow, glue, glue, and then some more gluing.
Friday, March 20, 2015
Glue, glue, glue, glue, lots of glue.
First thing today, finish up gluing the sides for the other half of the box.
That done, I “dry fit” the pieces to see approximately what the box will end up looking like.
I also wanted the two halves to be the same, so the box would lay flat when open.
When gluing up the sides, I went to the pain of matching up the wood grain as best as possible so that when the box was closed, it would look decent. I think I did a good enough job at that, especially since that was a last minute thought as I was arranging the sides for gluing.
I'm also planning on making the grain of the top and bottom flow as well:
So now it's just a matter of gluing the top and botton onto the sides of the box.
Between glue-ups, Bunny and I headed out to Lowes Home Improvement Store, as we both needed to pick up some hardware for the projects we're working on. In my case, that's home hinges and a latch of some kind. For such a simple task, it took a unreasonably long time to find the appropriate hardware for the job. The hinges were fairly easy, but finding replacement brass screws short enough so they wouldn't poke through the other side was tough (the packet of hinges came with screws about ½″ long—a bit too long for the width of the wood I'm using). Harder to find was an appropriate latch for the box. Most of them were just too large to use, and even the one I eventually bought, while it will fit, one side will extend up past the edge of the box.
But they're brass and they should look decent on the box.
Tomorrow, it's felt, felt, felt, and oh, did I mention the felt?
Saturday, March 21, 2015
Felt and Tung Oil
I was looking at my box today, concerned at just how bad it looked. But I was amazed at just how good it looked once I sanded the exterior (the interior will be covered in felt, so I didn't really see the need to sand the interior).
One tip when cutting felt—use a sharp blade. The sharper, the better. Then it was time to glue the felt to the interior of the box, which I did outside since I was using a spray adhesive.
I was not sure which approach I shoud take—either spray the felt and apply it to the box, or spray the inside of the box and apply the felt. So I tried both methods. For one half of the box, I sprayed the felt, and, well, spray adhesive is very sticky stuff. It got all over my fingers as I tried to maneuver the felt into place (for the record—I did the sides first, then the bottom). So for the other half of the box, I sprayed the interior of the box with glue, and that went everywhere. Then there was trying to position the felt into the wood perfectly the first time, least it immediately stick in some half-cocked position.
I'm not sure how I could have done it with less mess. I don't recommend either way, or rather, pick your poison when gluing felt.
But I got decent results.
Then it was on to finishing the box. Finishing oil, that is. Tung Oil Finish.
Bunny first handed me some latex gloves to protect my hands from the tung oil. She then handed me some old socks to use to rub the finish into the wood.
Previous two images courtesy of Bunny (as one hand was covered with a latex glove, and the other with a latex glove and a sock—there is no way I could operate an iPhone).
Now all that's left waiting for the tung oil finish to dry, apply another coat or two, and finally add the hinges and latch.
Sunday, March 22, 2015
Did an intentional truth slip past the corporate lawyers?
I used to log out of Facebook once I finished with the site because I realized they could track me with all the “Like” buttons on plenty of pages not on Facebook. But then I realized that was stupid, they can track me anyway through existing cookies, and even if I were to delete all Facebook cookies after logging out they could still track me via IP address (not that they do—in fact, I don't know if they do or not, but they could!).
I still log out though. Cargo cultish I know, but it makes me feel better, even when intellectually, I know it doesn't do a thing.
Which is why I found this ad so disturbing. Imagine that last line reading “we just did … and no, I don't mean for likes.”
Monday, March 23, 2015
The box.
Two additional coats of tung oil, a few hinges and a latch, and I have a finished wooden box.
The whole purpose of the box was to have a place to both store and use my dice for the twice-monthly session of D&D.
There was always the risk of a die rolling off the table and bouncing arond the floor, only to end up under the couch. Now though, I have a place to safely roll my dice.
On reflection, I think making an enclosed box and then cutting it open is the better way to go. The top and bottom of my box don't quite line up and I think it's due to making each half separately. Also, while I would like for the sides to be thinner, I doubt I could make it any thinner and still use the hinges and latch. As it was, even with the smallest screws I could find (3/8″), you can still just feel the screws just coming through the wood underneath the felt. I also think I would have preferred to use miter joints rather than butt joints. Perhaps next time.
Tuesday, March 24, 2015
A nice way to start the day
I always leave my SirusXM car radio set to the Jazz station. But for some reason this morning, it was set to the 90s station, and they happened to be playing Siouxsie and the Banshees Kiss Them For Me. It was a cool blast from my college days, and a nice way to start the morning.
Wednesday, March 25, 2015
A very good reason not to speed
It was impressive when the Mythbusters rammed a 650mph rocketsled into a car, but let's face it, in our day-to-day lives I doubt we'll be involved in a head-on collision with a rocketsled. Or anything moving at 650mph. But a collision at 120mph? (link via Instapundit)
Wow.
And not in a good way.
Thursday, March 26, 2015
The Fire Drill
There was a fire drill today at The Ft. Lauderdale Office of The Corporation. It had been announced ahead of time via email and came with a multipage document, outlining not only the evacuation plans, but who was doing what and where to meet (about half a block away).
So I was expecting something like:
[Main lights cut off. The entire Ft. Lauderdale Office of The Corporation is bathed in dim red emergency light.] AROOOOOOOOOOOGA! AROOOOOOOOOOOOOOOOGA!
The intercom system blares to life.] “ATTENTION! ATTENTION! THIS IS A FIRE DRILL! PLEASE EVACUATE THE BUILDING!”
“Go! Go! Go! Go! Go!”
“Aaaaaaahhhhhhh!”
“Run! Move, you maggots!”
“ATTENTION! ATTENTION! THE BUILDING'S SELF DESTRUCT SEQUENCE HAS BEEN INITIATED! PLEASE EVACUATE THE BUILDING! THIS BUILDING WILL SELF-DESTRUCT IN THREE MINUTES!”
“South office section clear!”
“North office section clear!”
“What's up with the central office section?”
“Run!”
“Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah!”
“Status! What's the status of the central office section? Report!”
“ATTENTION! ATTENTION! THE BUILDING WILL SELF-DESTRUCT IN TWO MINUTES!”
“Status!”
“Central office section clear!”
“ATTENTION! ATTENTION! PLEASE EVACUATE THE BUILDING!”
“Keep going!”
“Civilians have cleared the building, sir!”
“Keep going!”
“TEN … NINE … EIGHT … SEVEN …”
“Do we have everyone?”
“I'm counting!”
“Do we have everyone?”
“Yes!”
“TWO … ONE! HAD THIS BEEN AN ACTUAL EMERGENCY, THE BUILDING YOU HAVE JUST EVACUATED WOULD HAVE EXPLODED IN A HUGE FIREBALL AND ANYBODY WITHIN ONE HUNDRED YARDS WOULD BE DEAD! HAVE A NICE DAY!” [Unseen by the civillians, since they're all outside, the lighting resumes to normal inside the building.]
But alas, no. That was not the fire drill we experienced. It was more like:
“Attention. This is a fire drill. Please leave the buliding using the stairwell. That is all.”
“Oh, I guess we leave the office now.”
“Lunch?”
Friday, March 27, 2015
Some musings on serializing Lua with CBOR
Because it seemed like a fun problem, I decided to try my hand at writing a serialization library for Lua. It's not like there are many to choose from or anything. And besides, how long could it take?
[Many, many hours later—too many to mention.]
Well, that was fun.
I decided to use Concise Binary Object Representation as the binary format. The specification is straightforward, and surprising for a binary format, you can include quite a bit of semantic information.
Now, Lua itself has eight basic types; a few have subtypes:
- nil
- boolean
- number
- integer
- real
- string
- table
- function
- userdata
- light userdata
- full userdata
- thread
The nil type represents nothing—i.e. the absense of a value.
CBOR has an encoding for this,
so this is easy to handle.
The boolean type has just two values—true
and false
,
and again,
CBOR has an encoding for these two values as well,
so no problem there.
Lua's number type has two subtypes integer and real
(for Lua 5.3 and above—previous versions of Lua only had one numeric type,
real as that could handle integer values up to 9,007,199,254,740,989,
way larger than the 32-bit value of 4,294,967,296,
but the rise of 64-bit systems required Lua to adapt to handle integer values up to 9,223,372,036,854,775,807).
Again, CBOR has encodings for both integers and reals.
And support for the string type is also easy.
Even better, CBOR has two formats for strings,
one for text,
and another format for arbitrary binary data.
And then there's the table.
In Lua, tables are actually hash tables. There's an internal optimization if a table is treated as a real array, where the indices are consecutive integers starting from 1. Then the items are actually stored as an array. Even worse (or better, depending on your viewpoint), a Lua table can be used as both at the same time.
For example:
my_table = { 'alpha', 'beta', 'gamma', 'delta', 'epsilon', alpha = 1, beta = 2, gamma = 3, delta = 4, epsilon = 5, pi = 3.1415926 }
The strings “alpha”, “beta”, “gamma”, “delta”, and “epsilon” are stored in the array portion,
and if you take the length of my_table
,
you'll get back 5. So while you can reference my_table[3]
(which is “gamma”)
you can also reference my_table['pi']
(which is 3.1415926).
Now CBOR has encodings for arrays and hash tables,
an ARRAY
and a MAP
,
respectively.
So we can serialize Lua tables using CBOR.
But the issue is we really can't use the CBOR ARRAY
encoding for an arbitrary Lua table,
because we can't be sure if it's just a simple array:
my_array = { 'alpha' , 'beta' , 'gamma' , 'delta' , 'epsilon' }
or a simple hash table:
my_hash = { alpha = 1 , beta = 2 , gamme = 3 , delta = 4 , epsilon = 5 , pi = 3.1415926 }
or both! (Well, we could but it would be computationally expensive)
No, the best way is to handle tables as a CBOR MAP
.
Sure,
it wastes a bit of space including the index if the table is a simple array,
but we simplify the code,
and can deal with tables like my_table
.
There's one more issue we have to deal with—circular references:
x = {} x.a = "A" -- this is a shorthand notation for x['a'] = "A" x.b = { 1 , true , false , "hello" } -- a mixed array x.c = x -- we refer to ourselves x.d = x.b -- more than once
A naïve serializer will get caught in an infinite loop the second it tries to serialize x['c']
as x['c']
refers back to itself.
A smarter serializer will keep track and realize that x['c']
is also x
,
but now we come to the problem of encoding this in CBOR.
Fortunately, this is where the semantic information of CBOR comes into play. There's a standard extention to CBOR for references. This includes additional information into the output to designate the original value and later references to it. It does complicates the encoding and decoding process a bit (as I found out).
But so far, it was fairly easy.
And then there are functions …
Saturday, March 28, 2015
And twenty years to dig yourself a tunnel out of the Chinese fortune cookie factory
Sunday, March 29, 2015
Fozzie Bear IS Yoda!
It's a little known fact that Fozzie Bear actually played Yoda, the Jedi backwards talking Master, in the Star Wars films. Don't believe me? Here are rare photos of Fozzie's friends visiting him on the sound stage during the filming of Empire (link via Violet Impudence). Do you see Fozzie in any of those pictures? Hmmmmmmm?
And who in “The Empire Strikes Back” sounds awfully like Fozzie? Hmmmmmmmm?
With you, may the Waka-waka be.
Monday, March 30, 2015
But are there more museums than McDonalds, Starbucks and 7-11s combined?
There are roughly 11,000 Starbucks locations in the United States, and about 14,000 McDonald's restaurants. But combined, the two chains don't come close to the number of museums in the U.S., which stands at a whopping 35,000.
Via Instapundit, There are more museums in the U.S. than there are Starbucks and McDonalds – combined - The Washington Post
As weird as it may seem, it does appear to be true. Even lowly Brevard, NC, which has one (1) McDonalds and one (1) Starbucks, has three (count them, three) museums:
Heck, even Lincoln County, Nevada, (home to the Little A'Le'Inn) a county with a population less than Brevard, has two museums:
So yes, I can believe that there are more museums in the US than McDonalds and Starbucks combined.
Tuesday, March 31, 2015
More musings on serializing Lua with CBOR
So, where were we?
Ah, that's right … functions!
At first sight,
it looks like it would be rather trivial.
After all,
there's a standard Lua function,
string.dump()
,
which returns a binary representation of the given function that can be reloaded using load()
.
And CBOR supports encoding arbitrary binary data.
But there are issues with this.
First,
this only works for functions written in Lua;
functions written in C cannot be dumped,
and an attempt to do so results in an error.
For now,
we'll ignore this restriction.
Second,
the binary representation returned by string.dump()
is not portable.
Up till now, everything we've been encoding with CBOR has been portable with respect to computer architectures. But serialize a Lua function, and the receiving end would have to be the same architecture running the same version of Lua or else Bad Things™ will happen.
Another approach is to send the source code.
You can use debug.getinfo()
to obtain it,
but there are two issues with this:
one,
it doesn't always work
(there are cases were Lua can't determine the source,
say, if the function was loaded using the binary representation to begin with)
and second,
the source code won't include upvalues.
And now—a digression about variable scoping in Lua to explain what “upvalues” are.
Take, for example, this contrived example:
global_x = 5 local local_x = 3 function foo(param_x) local local_foo_y = 4 local function bar(param_a) return param_x * param_a + global_x * local_x + local_foo_y end return bar end
Function bar()
references four variables defined outside of bar()
itself,
global_x
(and I'll get to global variables in a bit),
local_x
,
param_x
,
and local_foo_y
.
And because functions in Lua can be passed around and returned like any other data type,
the values of those variables outside of bar()
need to be somehow associated with bar()
,
and that's what a closure (which is what Lua uses to represent a function) does—it collects variables outside the scope of a function (it “closes over” them)
and stores them so bar()
can still use them,
even if the scope the variable was defined in (like param_x
or local_foo_y
)
no longer exists.
Such variables are called “upvalues” in Lua.
So in this example,
local_x
,
param_x
and local_foo_y
are all upvalues of bar()
.
global_x
is not an upvalue,
becuse it's a global variable,
and they're handled differently.
In Lua,
a global variable is stored in a Lua table,
and a reference to that table is stored in an upvalue automatically generated if needed
(and can always be referenced by the name _ENV
):
bar = foo(3) info = debug.getinfo(bar,"u") -- get number of upvalues for i = 1 , info.nups do name,value = debug.getupvalue(bar,i) print(name,value) end
name | value |
---|---|
param_x | 3 |
_ENV | table: 0x89433c0 |
local_x | 3 |
local_foo_y | 4 |
You can see that Lua added the _ENV
upvalue automatically.
And it's this table where you'll find global_x
.
Now, back to our regularly scheduled discussion about serializing Lua functions.
So,
if we attempt to serialize the source,
all we would get for bar()
would be:
local function bar(param_a) return param_x * param_a + global_x * local_x + local_foo_y end
The “serialized” source would need to be modified to be:
local param_x local _ENV = _ENV local local_x local local_foo_y local function bar(param_a) return param_x * param_a + global_x * local_x + local_foo_y end return bar
That should work (and we still have to serialize the upvalues) but it's untested as I only serialized the binary representation (as I have to support that anyway). But this is something I should keep in mind, though.
Sorry, I digress.
Serializing the _ENV
table is concerning.
A stock Lua global environment contains about 150 items,
mostly functions but a few values like _VERSION
(which contains a string denoting the Lua version).
Even worse,
those functions are all written in C,
which can't be serialized.
And even if the functions could be serialized,
do you really want to serialize 150 additional items?
But we can't just skip serializing _ENV
,
as it could be modified to provide a custom “global environment” for the function being serialized,
although that custom _ENV
could still refenence existing functions written in C!
What's really needed is a way to reference the data we need.
Well, CBOR does have that semantic tagging we've already used. So why not a bit more semantic tagging?
The following table:
{ print = print, tostring = tostring, tonumber = tonumber, io = io }
will basically get encoded as:
CBOR_TAG shareable CBOR_MAP 4 -- number of items in the map CBOR_TEXT "print" CBOR_TAG __Lua CBOR_TEXT "print" CBOR_TEXT "tostring" CBOR_TAG __Lua CBOR_TEXT "tostring" CBOR_TEXT "tonumber" CBOR_TAG __Lua CBOR_TEXT "tonumber" CBOR_TEXT "io" CBOR_TAG __Lua CBOR_TEXT "io"
Upon decoding, a string tagged as __Lua
will be translated to the appropriate Lua value of the given name
(which means searching through the global variables for a variable with the given name).
This solves sending the standard global environment over and it kind of,
somewhat,
sort of,
solves serializing C functions—as long as the C function exists when the function is deserialized.
Well, it's a solution, anyway.
To recap,
not only do we need to serialize the Lua function,
but its upvalues as well.
I decided to use a CBOR array for this.
The first item is the function itself,
with the rest of the items in the array being the various upvalues of the function.
And thus,
our example function bar()
is encoded:
CBOR_ARRAY 5 -- number of items in the array CBOR_BIN 1B4C7561530019930D0A... CBOR_UINT 3 CBOR_TEXT CBOR_TAG __Lua "_G" CBOR_UINT 3 CBOR_UNIT 4
There is still one slight problem though—this assumed that global_x
exists as a global variable when deserializing the function.
Unfortunately, there isn't an easy answer to this,
except “better make sure it exists.”
So that just leaves the Lua types userdata and thread left to encode …