Thursday, January 01, 2015
The Year is dead! Long live the Year!
Given that it sounds like a war zone outside, and it's not the Fourth of July, there are only two reasons I can see for this:
- anti-police factions are holding their position against the police or
- it's New Years Day and people are celebrating the start of 2015.
Frankly, given recent events, it very well could be the start of a revolution (which won't be televised; it will be Tweeted) but seeing how the calendar just flipped over, I do believe it's just the celebration of the New Year.
Here's to 2015!
Friday, January 02, 2015
The fultility of making resolutions
I resolved not to make any resolutions, which meant I lost the very second I made it.
Funny how that works.
Fireworks from a different perspective
In the late 90s, I found myself flying home on the night of July 4th. It was incredible seeing so many fireworks shows from high above—everywhere I looked, there were tiny multicolored explosions. It was an incredible experience to see over a hundred fireworks shows, live, on one night.
Even more impressive is this video (link via Instapundit) of a fireworks show, filmed alongside exploding fireworks! I'm very surprised that the drone survived such an ordeal.
Update at 12:36 AM on January 3rd, 2015
From my friend Jeff Koecher, that video was shot in West Palm Beach, Florida, about 30 miles north of Chez Boca.
Saturday, January 03, 2015
“Bow to my awesome power of zoning!”
Just what I need—a web-based version of Sim City (link via HackerMonthly). There go a few hours terrorizing simulated citizens with my dictatorial mayorial powers!
Muahahahahahahahahahahahahahaha!
But at least it wasn't a link to Cracked (WARNING: DO NOT CLICK ON THAT LINK IF YOU VALUE THE REST OF YOUR DAY!).
Sunday, January 04, 2015
'Tis easy to become an aluminum smith
Who knew it was so easy to smelt aluminum at home?
Monday, January 05, 2015
Notes on an overheard conversation between two people assembling a table saw
“It says to use four screws, but there are seven holes in this rail.”
“So?”
“So? There are more holes than screws.”
“Perhaps they use the rails for different table saws.”
“Okay, but they don't say which holes to use.”
“You use the holes that line up. See? That hole lines up, and that one, and that one, and that one.”
“But … but … how do you know this stuff? It's because you're an engineer, right?”
“Yup. College. It's a painful procedure where they physically implant engineering books into the head of engineering students.”
“Pbbbbbbbt.”
“You're welcome.”
“Okay, hand me that fence.”
“Here you go.”
“This is supposed to go between the table and the rail.”
“Really?”
“Yes.”
“There's no way it can fit. A piece of paper can't fit between the table and the rail. But place it like this and it still reaches across.”
“But the instructions say that bit is supposed to fit between the rail and the table.”
“Hmm … perhaps that bit sticking down was placed on backwards … ”
“No, I think it's correct.”
“Really? Let me see the instructions … ”
“See?”
“Oh. Oh!”
“Oh?”
“Yes, oh. I put the rail on wrong.”
“Do tell … ”
Tuesday, January 06, 2015
… and this bug exists because of a work-around for that bug …
Sigh.
The last day at work in 2014 (Debtember 18th), I spent it
running yet another IOT, which involves running
tcpdump
to capture the network traffic on our end to verify
that we receive and send the data properly. After running a test, I would
load the resulting capture into wireshark
, filter for the
SIP protocol only to
find—
Nothing.
“Project: Sippy-Cup” was
getting the packets and responding correctly—well, as “correctly” as these things go, but I was not
seeing any packets under wireshark
, no matter what I did. But
the whole test setup is so jury-rigged that it wouldn't surprise me at all
if we were, in fact, doing NAT over avian
carriers that it seemed rather pointless to spend the next few hours
trouble shooting my inability to do network captures when the other
participants were able to capture enough of the transaction to let us
continue running the test.
Especially as I was one day from retirement a few hours
away from a two-week Christmas vacation.
And then today, I learned that we were, in fact, capturing data.
Why was wireshark
not showing the packets?
Because I was telling wireshark
to filter on SIP, which defaults to port
5060. We were running our SIP component on port 5061, because of some odd-ball
router on our network that oh-so-helpfully looks for SIP traffic and attempts to proxy it
anywhere else than our SIP component.
And because we were running on a non-standard port,
wireshark
wasn't showing us the proper packets as it was
looking only for packets on port 5060.
I swear, I think IP-over-avaian-carriers would be easier to deal with.
No, a reality TV show about computer hacking can be totally accurate and not boring at all. No, really.
So apparently, this is happening:
SyFy just announced a new reality TV show called Hackers. It's about hacking, naturally, and the network promises it will be awesome and exciting. (Spoiler: Hacking is incredibly boring.)
The new, unscripted show does sound interesting. It's unclear if the new SyFy series has anything to do with the 90's classic film Hackers. SyFy will produce Hackers with Relativity Television (of Catfish fame) and promises to “take viewers deep inside the shadowy and dangerous world of high-tech hackers for the very first time.” While verbs like “shadowy” and “dangerous” certainly ring true of cyber security in the age of the Sony hack, that doesn't mean that filming hacker-types staring at dark screens makes for entertaining television for the general population. It almost definitely doesn't.
Via Reddit, The New Hackers Reality Show Would Be Great If Hacking Weren't So Boring
You really want to see what hacking is like? Watch the first episode of “The Scene.” While the story (and music) of “The Scene” is compelling (enough to carry me through the season), it's not compelling to watch (it was tiring having to pay so close attention and read everything on the screen to keep up with the “action”). That's a hacking movie.
This?
I'm curious enough to watch an episode or two—I mean, who doesn't love train wrecks? (Um, besides the ones involved in a train wreck?) But I can't see this being any good.
Or lasting that long.
But hey … you know … HACK THE PLANET!
Wednesday, January 07, 2015
Notes on an overheard conversation at The Ft. Lauderdale Office of The Corporation
“I have a problem.”
“And that problem is?”
“I have two remote meetings to attend, scehduled at the same time.”
“Any meeting that can start without you isn't worth attending.”
“They can't start without me.”
“Hmm … have you considered using both your cell phone and desk phone, at the same time?”
“Really?”
“Put one ear bud from one phone in one ear, one ear bud from the other phone in the other ear.”
“That could work.”
“Really?”
“I'm going to try that.”
“…”
Thursday, January 08, 2015
I think the problem is that without Steve Jobs, there's no one at Apple that can say “No, we aren't releasing this.”
A few months ago, I think back in late September or early October, I needed to reinstall Linux on my work laptop due to a hard drive failure. Over the following week or so, I came to the conclusion that Ubuntu had jumped the shark and that whatever they were trying to pass as a “Linux Laptop Distribution” (Ubuntu's Ulcerating Unicorn) was probably a secret plot by Microsoft to discredit Linux.
The upshot was that I got a new laptop a few weeks later—a shiny new Macbook Pro with all the bells and whistles. It took a few days to get the then-latest version of Mac OS-X, Mavericks, configured to my liking (and really, Apple? Near arbitrary names for versions? I could never remember if Jaguarundi was newer than Ocelot or was it Puma, Ocelot and then Jaguarundi).
There was only one problem—it couldn't log onto The Ft. Lauderdale
Office of The Corporation's local wireless network. The wireless adaptor
works (I was able to hook up to the local wireless network at Chez Boca) but
for some reason, it just refuses to join The Ft. Lauderdale Office of the
Corporations's local wireless network. In my opinion, it's not that big of
a deal as I've always been able to use Ethernet. But it was an issue to my
manager, S, so it came to pass that today was The Day to fix it by
installing the latest version of Mac OS-X, Rabid Wombat
Yosemite.
It's a testament to Apple that I spent more time trying to live
with Ubuntu's Ulcerating Unicorn than I did with Apple's Rabid
Wombat Yosemite. Not only did this not fix the wireless network
issue, but part of the menu bar was constantly flashing for no apparent
reason; I had to constantly
reinstall DoubleCommand (I need DoubleCommand so I can use
my
preferred keyboard) but the final straw was maximizing a window.
Previously, when you maximize the window, it takes up the whole screen,
minus the menu bar at the top. But under Yosemite, the now flat, dull green
button (I guess to harmonize with the new trendly look of Apple's iOS 8
for the iPhone/iPad) the window took up the entire screen,
obscuring the menu bar!
At that point, I pulled all the cables out of the laptop and unceremoniously handed it to the IT person, demanding it be put back to Mavericks. I hate to say it, but I think Yosemite is worse than Windows. Apple Mac OS-X has not only jumped the shark, it has jumped the Discovery Channel's Shark Week.
Friday, January 09, 2015
The True Facility in the Middle of Nowhere
For some obscure reason, Bunny wanted us to go away on a weekend excursion. Last week she asked me if there was any place I wanted to visit. Not having any particular destination in mind, I decided to search for “weird places to visit in Florida,” threw a metaphorical dart and proudly announced “Solomon's Castle,” a museum-restaurant-bed-n-breakfast in the middle of nowhere.
The last sixteen miles are long unnamed county roads northwest of Arcadia, itself pretty much in the middle of nowhere, but it's a bit of civilization in the middle of nowhere. The last mile consists of driving down a dead end street, past the “END OF PAVEMENT” sign (which is a lie—it's paved all the way) to a large iron gate marking the entrance to Solomon's Castle. We parked, and headed on the yellow brick path (asphalt with yellow bricks stamped out in paint) towards the castle.
It is impressive upon first sight and very hard to miss, seeing how it's clad in aluminum from top to bottom. We passed the two suits of armor and entered the castle.
Our timing was a bit off as we arrived just as the place was closing. They were expecting us, as Bunny had already arranged for us to stay at this museum-restaurant-bed-n-breakfast, but Dean, our host, was over in the “Boat-in-the-Moat,” a 65' replica of a Spanish galleon moored in the moat (every castle has a moat, right?) which serves as a restaurant.
We walked over to the gangplank and boarded the Boat-in-the-Moat. We met Dean while the restaurant was in the process of closing. Dean then lead us back down the gangplank and around the castle to the back, where the Blue Moon Room was located.
I suspect that the stairs (outside the building) leading to the Blue Moon Room might not quite meet OSHA standards as there was some heavy swaying as we climbed the stairs [It did not “sway.” —Bunny] [Oh yes it did. Swayed like RuPaul at a drag race. —Sean] [It did not, Mr. Hyperbole. —Bunny] [Did too! —Sean] [Did not! —Bunny] [ENOUGH! —Editor]. Dean then opened the double doors to our suite.
The Blue Moon Room is the second best bedroom in the castle—the best belonging to Howard Solomon, owner and builder of (we learned later) the whole compound. Our room, the Blue Moon Room, is not only the second best, but the only other bedroom in the castle (as bed-n-breakfasts go, it's rather small in the “beds-to-rent” department).
The Blue Moon Room was really nice. Kitchen. Sitting area. Nice-sized bed.
Huge bathroom. And a definite “Blue Moon' theme going on, what with the color scheme and moon imagery going on (along with a sun motif—honestly, there were scores of suns and moons all about the room).The one oddity of the room we instantly noticed was a slight incline in the floor. I wouldn't think a one degree incline would be so noticable but there it was, a definite list to the south.
Another oddify of the room slowly dawned on us. Back in the Boat-in-the-Moat, I had asked Dean about wifi access and Dean was a bit vague about it. He acted like he knew what the term “wifi” meant, and he even said it existed somewhere on the premises, but he didn't really say outright that we had wifi access. But no, we didn't. No signal at all. But another thing we had noticed—there was no cell signal either. It then hit me---the entire building was wrapped in aluminum.
Wrapped. In. Aluminum!
We were sitting in a large Faraday cage!
Talk about being in the Middle Of Nowhere.
Dodging bunrabs in the dark
After settling into the Blue Moon Room we rested for a bit before heading out to dinner. Given that the restaurant at Solomon's Castle closed at 4:00 PM, that meant we had to drive some twenty miles back to civilization—in our case, Arcadia. Dean had warned us that it would be dark and suggested we take along a flashlight, one being provided for us in the room.
“Dark” would be an understatement. I can't recall the last time I saw darkness that dark. Sure, it made for a spectacular view of the night sky (especially since the moon was still below the horizon) but we still had to navigate those swaying stairs [They didn't sway! —Bunny] [Did too! —Sean] [Snot! —Bunny] [Too! —Sean] [ENOUGH! —Editor]. Fortunately, our iPhones had a built-in flashlight app to augment the provided flashlight so we could safely navigate the stairs and flood the forest alongside them to assuage our fears of the noisy wildlife infesting the immediate area around the castle.
And driving along unnamed county roads unlit by modern technology was fun, although not as fun as driving along unnamed county roads unlit by modern technology in the mountains (which I have done, but that was a few years ago in North Carolina), but still, fun. It took me a few minutes to learn how the brights work in the car since that's not something I normally have to use here in Lower Sheol. Even better—we had to avoid opossums, rabbits (“bunrabs” as Bunny calls them), a fox (!) and one rather large and impressive looking deer (well, that last we didn't have to avoid—it was standing off to one side of the road, thankfully). That was more wildlife than I've seen driving on mountainous, unnamed county roads in North Carolina.
Educating the hoi polloi
There is one further observation I would like to make for today. Of the two restaurants where we ate, lunch at a diner in Okeechobee and dinner at a diner in Arcadia, both had paintings in the men's room.
Paintings. In the men's room!
Is that some sort of central Florida diner thing or something? Trying to civilize the hoi polloi in fine art through diner men's rooms?
I want to know.
Saturday, January 10, 2015
Phenomenal sized bathroom, itty bitty fixtures
I need to talk about the huge bathroom in the Blue Moon Room.
Huge. Easily twice the size of ours at Chez Boca. But the sink (not shown in the picture)? Tiny. That toilet? A midget would find it nice. That shower stall?
Nothing at all like the one at the Red House Inn in Brevard, which could easily fit two or more people. Nope. This one barely fit one and even then, it took careful manoeuvering to turn around.
Yeah, for the size of the actual room, you think they could have used slightly larger fixtures. Heck, moving the wall closer to the toilet by six inches, and putting the shower curtain across the room (across the rug that's there now) and making that entire portion of the bathroom the shower would have done wonders.
But no.
We get a bathroom fit for the extras from “The Wizard of Oz.”
Art, and a lot of it.
Bunny and I had our complementary continental breakfast (with hot chocolate!), and were putting our luggage in the car when we noticed just how hopping Solomon's Castle was by noon:
We then caught the next tour of the castle, a museum containing mainly the art work of Howard Solomon, who has, shall we say, a rather punny sense of humor.
After the tour, we were exhausted and decided to just get on the road and head on back to Chez Boca. Contrary to some of my snarkier remarks about the place, both Bunny and I enjoyed our stay and were glad we went. The rate we paid to stay overnight wasn't that bad (I've paid more to stay at some bed-n-breakfast places over the years) but I would really recommend just coming for the museum and maybe the restaurant (what we had we liked, but it was a very light breakfast; we didn't have lunch there, but the reviews I have seen for the restaurant portion have been very favorable) if you happen to be in the area.
Sunday, January 11, 2015
There's just no explaining 2014
It was a year of mysteries. To list some of the more baffling ones:
A huge airliner simply vanished, and to this day nobody has any idea what happened to it, despite literally thousands of hours of intensive speculation on CNN.
Millions of Americans suddenly decided to make videos of themselves having ice water poured on their heads. Remember? There were rumors that this had something to do with charity, but for most of us, the connection was never clear. All we knew was that, for a while there, every time we turned on the TV, there was a local newscaster or Gwyneth Paltrow or Kermit the Frog or some random individual soaking wet and shivering. This mysterious phenomenon ended as suddenly as it started, but not before uncounted trillions of American brain cells died of frostbite.
An intruder jumped the White House fence and, inexplicably, managed to run into the White House through the unlocked front door. Most of us had assumed that anybody attempting this would instantly be converted to a bullet-ridden pile of smoking carbon by snipers, lasers, drones, ninjas, etc., but it turned out that, for some mysterious reason, the White House had effectively the same level of anti-penetration security as a Dunkin’ Donuts.
LeBron James deliberately moved to Cleveland.
Of course not everything that happened in 2014 was mysterious. Some developments—ISIS, Ebola, the song “Happy” were simply bad.
Via Instapundit, Dave Barry's Year in Review: There's just no explaining 2014 | The Washington Post
Dave Barry sums up 2014 better than anyone else can. So what if this is a bit late (my posting it here, not when Dave Barry wrote it)? I'm still trying to get a hang of 2015, which might not happen until 2016 comes rolling around …
Monday, January 12, 2015
Some might view this as a window into doom
Acrophobia is the fear of heights. We certainly hope you don’t have it. If so, a trip to the Zhangjiajie and Tianmen mountains in China’s Tianmen Mountain National Park may not be advised. However, if scenic routes that will get your heart racing and truly exhilarating views are what you are after, then this may be for you. The appropriately named Walk of Faith is a glass walkway that is exactly what it says on the tin. Save for the hand rails and metal and concrete supports, the 61 ft. walkway up the side of the mountain is entirely glass, allowing walkers to view the staggering height they are at, right beneath their feet, which is some 4,700 ft. above sea level.
Via MyGoogleFaceSpacePlusBook, Transparent Torture, The Walk of Faith and Seriously Scary! - Industry Tap
Cool idea, but in a word: OH XXXX NO!
Tuesday, January 13, 2015
Zombie outbreak? Head towards the zoo
Zombies are scary. We humans are evolutionarily pre-programmed to abhor the dead bodies of our own species. It's a natural reaction, helping healthy individuals avoid fatal pathogens.
The thought of being eaten alive is a natural fear, and when it's your own species doing the eating, it's even more terrifying.
Relax. Next time you're lying in bed, unable to fall asleep thanks to the vague anxiety of half-rotten corpses munching on you in the dark, remember this: if there was ever a zombie uprising, wildlife would kick its ass.
Zombies vs. animals? The living dead wouldn't stand a chance - Boing Boing
This is an article for my friend Hoade. It appears that the safest place to be in the zombocalypse is a zoo!
Who'd a thunk it?
Wednesday, January 14, 2015
Well this is a nice thing to come home to
I get home, and the monitor on my Linux system is wigging out. This is not good, as this is the third monitor on the system since 2009.
Also, the computer is quite loud, louder than normal, which means, it's hotter than normal, which isn't good. I never did find out what was constantly running, but I did isolate the issue with the monitor—it's not the monitor. That's the good news. It's the video card.
Lovely! I cooked the video card to death!
Sigh.
And in the process of troubleshooting all this, the shelf the computer was sitting on (attached to the computer desk) broke. Or rather, the caster beneath the shelf wrenched itself free, causing the shelf to collapse under the weight of the computer.
Double sigh.
At least the computer itself is fine. The shelf is in the process of being repaired (should be done by tomorrow) but the replacement video card won't get here for another week or so.
Thursday, January 15, 2015
A quick DIY computer desk shelf repair
Bunny's brother is visiting this week from Seattle. He took one look at the broken computer desk shelf, measured the broken caster (it ripped out from the bottom of the shelf) and the length of the shelf. He then went to the garage, where Bunny has all the wood working equipment. He selected a scrap piece of wood, ripped it to 2½″, then cut it to length (it helps to have a table saw for this). He then scribed a curve on each end and with the bandsaw, cut the corners off. A quick pass with the belt sander to round off the edges of the board. A bit of wood glue, some clamps, scraping off the the excess glue with a paint scraper and all that was left was to wait for the glue to dry.
And yes, it happened pretty much that fast. Well, except for the waiting for the glue to dry.
Oh, I almost forgot to mention the strip of felt along the bottom. The shelf now has better support and it can still slide out of the way in case I need access to the cables.
Now I'm just waiting for the new video card to arrive.
Friday, January 16, 2015
Never trust input, and you can still leak stuff with garbage collection
We're still IOT testing (yes, five months, but we're doing IOT testing with The Monopolistic “We Don't Have To Care, We're The” Phone Company where things move slower than molasses in Antarctica) and I'm finding it interesting (in the Chinese sense of the term) to see “actual real world data” rather than the “pristine theoretically correct data” we've been using for testing (because in theory, there is no difference between theory and practice, but in practice …).
For instance, I've been reeiving reports that “Project: Sippy Cup” (which implements a subsection
of SIP) was only processing less than
5% of the OPTIONS
requests (which informs the other side if
we're ready for processing, but also informs the other side what other type
of requests we support). Odd, as our internal testing was handling every
OPTIONS
request we sent.
So I added some addtional logging:
- Log everytime we receive a packet.
- Log everytime we get an
OPTIONS
request. - Log the results of sending a reply to an
OPTIONS
request.
and I get back:
Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9901: OPTIONS from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9902: send OPTIONS response to ip6:[fc00:0:60:8a1::9]:5060 datasize=581 sentbytes=581 err=Success Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9901: OPTIONS from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9902: send OPTIONS response to ip6:[fc00:0:60:8a1::8]:5060 datasize=581 sentbytes=581 err=Success Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9901: OPTIONS from ip6:[fc00:0:60:8a1::9]:5060 Sippy-Cup9902: send OPTIONS response to ip6:[fc00:0:60:8a1::9]:5060 datasize=581 sentbytes=581 err=Success Sippy-Cup9900: received from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9901: OPTIONS from ip6:[fc00:0:60:8a1::8]:5060 Sippy-Cup9902: send OPTIONS response to ip6:[fc00:0:60:8a1::8]:5060 datasize=581 sentbytes=581 err=Success
At first, I thought perhaps the output sent was filtered to just those
three messages and some other messages, like, “Sippy-Cup0014:
ip6:[fc00:0:60:8a1::9]:5060 sent garbage
” or “Sippy-Cup0055:
ip6:[fc00:0:60:8a1::9]:5060 sent an unknown call
” were filtered
out.
Nope. What I saw is what got logged.
Fortunately, the actual network packets had been captured so I could look at them. And I immediately saw the problem.
“Project: Sippy-Cup” is written in Lua, since it's easier to parse text in Lua
than in C (it's easy to parse text with LPeg), and each request
is handled in a Lua
coroutine—it makes following the code a lot easier since it can be
written in a straight-forward procedural way rather than with callbacks or
complex state machines and what not. The only trick here is that for any
operation that might block, the code has to manually insert a call to
coroutine.yield()
to let another coroutine run (if there are
any to run).
In SIP, all the
messages pertaining to a phone call each have a unique identifier, and it's
this identifier I use to know which coroutine to run when a message comes in
(or spwan a new coroutine if this is a new call). The OPTIONS
request isn't really part of a normal call, but I had assumed, like other
SIP requests, that
they too, would have a unique identifier.
It turns out that no, The Monopolistic “We Don't Have To Care, We're
The” Phone Company is gladly using the same “unique” identifier for each
OPTIONS
request, mostly … occasionally they'll generate a
new “unique” identifier just to keep us on our toes.
Or something like that.
Okay, that did reveal the actual bug though—I wasn't releasing
the reference to the coroutine when processing an OPTIONS
request. Had I done that, it wouldn't have mattered, since I wouldn't have
a reference to a coroutine with that particular “unique” identifier, and a
new coroutine would have been created to handle the OPTIONS
request.
Which goes to show you that not only is input weirder than expected, but even in a language with garbage collection, you can still leak resources.
Japanese wood porn
There's a Japanese style of woodwork called sashimono where no nail or glue is used when making joints. Just intricate cuts using scores of custom saws and planes (no power tools here) to make blind joints (joints that do not show).
It's insane.
And it's incredibly beautiful.
I asked both Bunny and her brother (who's currently visiting) if they would take up sashimono, and in unison, both said “Oh XXXX no!” They're perfectly happy to use power tools and typical jointery for their woodworking projects, not that I blame them.
Saturday, January 17, 2015
Blackhat
Bunny, her brother and I went to see “Blackhat.” Wonderful … another Hollywood hacker film.
The gold standard for hacker films is “WarGames. “Sneakers” is good (it's a lovely character piece) but as far as hacking goes, it's a bit questionable. I love “Hackers” but not because it's good, but becuase it's so cheesily bad! (“HACK THE PLANET!)
Other hacker films? “The Lawnmower Man” was just bad. And the only thing I remember about “The Net” was that it starred Sandra Bullock (and yes, I saw this is the theater). The rest? I haven't found them all that memorable (oh, I remember seeing “Swordfish, but the fact that I had to be reminded about it says something about the film—or me, but I digress).
So yeah, another Hollywood hacker film.
I went into the film with low expectations, which was a good thing, as this was better than I expected. Visually, the film is beautiful, and it's very atmospheric (read: ssssslllllllooooooooooooooooowwwwwwwwwwwwwwww) but I didn't really mind it that much (although Bunny did lean over and asked if I felt this was a slow movie). The hacking scenes were probably the best in a long time (not since “WarGames” has hacking been protrayed this well). Realistic command line action (for the most part—some bits of HollywoodOS peeked through, but not enough to be terribly distracting), and some other aspects of hacking that don't get much screen time, such as social engineering and physically being on-site (one scene required the heros to obtain data by physically extracting a hard drive from a computer).
Some of the gun fights were a bit over the top (as Bunny's brother mentioned on the way home—if those guns could shoot through cargo containers, there's no way the heros could have survived) but hey, it's Hollywood. Over the top gunplay is de rigueur these days.
The one big glaringly bad thing about the film is the villian. He's given very little screen time (fifteen minutes top?), his motivation is nothing more than simple greed (no, really. It's not even stated outright what his motivation is, other than he steals $73,000,000 to fund another hack to steal even more (the potential amount is never given) in an odd scheme that doesn't make real sense when you think about it for long). The villian is so inconsequential I can't even find out who played the villian. Nor could I find the name of the villian (the flunky? Yeah, he has a name, but Mr. Big? Nope). But perhaps that's the point? That it's some nameless hacker that can cause physical destruction on a mass scale?
I don't know, but it bothers me.
But is this the best cyber movie ever? For me—no. The best is still “WarGames” (to my knowledge, the only hacker film to inspire an actual hacking technique), followed by “Sneakers” (I just love the character interactions in that film). Heck, given a choice between this and the cheesefest that is “Hackers,” I'll take the cheesefest every time. But aside from those three? Yeah, it's a lot better than Hollywood has tended to make.
Sunday, January 18, 2015
“… the street finds its own uses for things.”
The Nintendo Power Glove may have failed as a game controller, but animator Dillon Markey has given it a new lease on life. With a few modifications and design tweaks, he’s revived the Glove and put it to use as an ingenious stop-motion animation tool.
Via Zed Shaw, Animator uses Nintendo Power Glove for stop-motion animation | Digital Trends
Back in college, my friend Ken thought that the Nintendo Power Glove would be great for virtual reality applications, and I think he even went so far as to obtain one, but I don't recall it ever being that great for his intended purposes.
It also appears that even for its intended purposes, it failed.
But it's great to see someone finding a unique use for it.
A little football rivalry
Bunnny and her brother are die hard Seahawks fans. Our neightbor across the street is a die hard Packers fan. After today's game, odddly enough, our neighbor wanted to talk about anything other than the game.
Monday, January 19, 2015
Cellphone guts for the curious, Part II
Two years ago I published an email I received about the internal workings of a cellphone, and today, I received yet another email, from a fellow cow-orker about that previous email:
- From
- BXXXX XXXXX <XXXXXXXXXXXXXXXXXX>
- To
- <sean@conman.org>
- Subject
- Re: Cellphone guts for the curious …
- Date
- Mon, 19 Jan 2015 12:08:13 -0500
Sean,
In reference to: http://boston.conman.org/2013/01/22.2
I passed this link along to a friend who is as technically talented as XXXX, but who is also as politically astute as he is technically astute. Here is his response:
Last time I checked, they are separate because the FCC says they have to be separate.
There was huge debate between focus and the phone manufacturers. The phone manufacturers wanted a single processor for both the air processor and the phone/app gui. The FCC said no because of the possibility of changing the radio firmware.
Disclaimer: I am not offering this for contradiction; just FYI and for discussion (if you wish). Both he and XXXX are way beyond me in this area, so I offer no opinions or views of my own. In other words, I am all ears.
While the FCC has jurisdiction over radio transmission, I think the separation of general purpose CPU and baseband processor has more do to with recertification than a legal mandate to be separated.
But I don't work for a cellphone manufacturer, so I might be mistaken.
'Tis easy to make an aluminum foundry
A few days ago I posted a video about smelting aluminum, and now:
… how to make the foundry to smelt the aluminum.
Tuesday, January 20, 2015
The upper bound on the number of test cases in the new regression test is 2,359,296, but it'll probably, hopefully, be less than that.
We're coming up with a new regression test at work that kind of, maybe, combines both the original “Project: Wolowizard” and the new “Project: Sippy Cup” and my manager, S, came up with 11 variables to test; A with values A1, A2 ‥ A8; B with values B1, B2, B3, B4; C with values etc. And multiplying out all the possible values of all the variables, I end up with a potential 2,359,296 possible test cases.
Now, some of the cases aren't possible. For instance, values D1, D2, D4and D6 can only be tested with value H1 (or rather, with those values of D, H1 is the only value H can have), while D3, D5, D7 and D8 can only be tested with values H2, H3 and H4. So, just looking at D and H, it's … um … let's see … there are two parties involved, both with D and H values, and does it make sense for P1D5 to call P2D5? Um … well, in this case, H doesn't really apply to P1 so out of a possible 32 combinations, only … um … 24 really apply.
I think.
Yeah, it's going to be real fun trying to puzzle out all the cases.
The new video card: the good, the bad and the ugly
The good news: The new video card arrived.
The bad: it's the wrong XXXXXXX card! I ordered a Dell nVidia GeForce 7300 LE. I received an ATI Technologies Inc RV370. Grrrrr.
The ugly: it does work, but it doesn't work at the resolution I require (or I don't have the proper drivers).
Back it goes, and we enter round two.
Wednesday, January 21, 2015
More alternatives to stream punk computers
I had thought I posted Jeffrey Stephenson's custom computer cases, but no, I had linked to Love Hultèn, who also does beautiful computer cases.
Thursday, January 22, 2015
It's over 9,000!
At work, we've been working to reduce the number of test cases and it looks like we have just a bit over 9,000 (it's an Internet meme-thing). It's over the 5,000 our manager was expecting, but it's far less than the 2,359,296 theoretical maximum number of test cases we could have had.
Now, it's off to document all 9,120 cases …
Friday, January 23, 2015
Generating regression test cases
We miscounted—there are, in fact, 9,697 test cases so far.
My manager, S, has been responsible for generating the test case descriptions, stuff like:
Section 1
Originating device is XXXXXXXXXX XX XXXXX and is calling a terminator with our client on the device test cases.
- Terminating device can have the following features: XXXXXXX, XXXXXXXXXXXXX (2 options)
- Originating device can be a
sip:
ortel:
URI (2 options)- Terminating device can be a
sip:
ortel:
URI (2 options)- Originating can have XXXXXXX present or not (2 options)
- Terminator's XXXXXXX state is not applicable (1 option)
- Originating device can have two options for XXX (2 options)
- Terminator's XXX state is not applicable (1 option)
- Originating device can have XXXX values of XXXXXXXXXX, XXXXXXXXXXX, XXXXXXXXXXX (3 options)
- Terminator's XXXX state/capability is not applicable (1 option)
- XXXXXXXX XXXX XXXXXXXXXXX is either present or not for the Originating device (2 options)
- Terminator's XXXXXXXX XXXX XXXXXXXXXXX is not applicable (1 option)
- Originating Type of Number can either by CDMA or LTE (2 options)
- Terminating Type of Number can be: cdma+XXXX, cdma, lte (3 options)
- Terminating XXXXX can be: XXXXXX, XXXXXXX, XXXX (3 options)
- Originators XXXXX is not applicable (1 option)
- Total number of test cases in this section = 2 × 2 × 2 × 2 × 2 × 3 × 2 × 2 × 3 × 3 = 3456.
It's my job to generate the data required to run all these test cases, which means I need to run through the various variables and all their values, generating the data required to run the test and there's no better way of doing this than to brute force it. I could have written the code as:
-- variable names changed to protect the innocent. for _,A in ipairs { false, true } do for _,B in ipairs { 'tel' , 'sip' } do for _,C in ipairs { 'tel' , 'sip' } do for _,D in ipairs { false , true } do for _,E in ipairs { false , true } do for _, F in pairs { 'opt1' , 'opt2' , 'opt3' } do ... test_case(A,B,C,E,E,F, ... ) end end end end end end end
and while that does the trick, it's verbose and it uses a convention
(using '_' to designate a result one doesn't care about, and in this case, I
don't care about the first return result from ipairs()
) that
the other programmers here might not immediately pick up on (as far as I
know, I'm the only one using Lua at the Corporation).
No, I feel it's better to show my intent. I want the code to look like:
for A in bool() do for B in list { 'tel' , 'sip' } do for C in list { 'tel' , 'sip' } do for D in bool() do for E in bool() do for F in list { 'opt1' , 'opt2' , 'opt3' } do ... test_case(A,B,C,D,E,F, ... ) end end end end end end end
And that's exactly what I did. The generic for
loop in Lua
is defined
as:
for
variablein
function, state-variable, initial-value
where function is repeatedly invoked as
function(state-variable,initial-value)
until the it returns
nil
; when the result isn't nil
, it's assigned to
the main loop variable. In the first example, ipairs()
(a standard Lua
function):
function ipairs(list) local function next_value(state,var) var = var + 1 if var > #state then return nil else return var,state[var] end end return next_value,list,0 end
ipairs()
returns a function that takes a state variable (in
this case, the variable list
which should be an array) and an
initial value (0) and this is repeatedly called until that function returns
nil (here, when the index exceeds the number of items in the array).
For what I wanted, the function list()
is easy:
function list(L) local function next_item(state) state.n = state.n + 1 return L[state.n] end return next_item,{ n = 0 } end
The function next_item()
only cares about the state, which
holds an index into the list (it's stored in a table because this is the
only way we can modify it) which we increment and return that item from the
passed in list L
. We only return two values, the function and
the state. The missing third value will be nil
, which we don't
care about. The one for cycling through booleans, bool()
looks a bit more complicated:
function bool() return function(_,value) if value == nil then return false elseif value == false then return true else return nil end end end
Here we just return a function; the other two values for
is
expecting will then become nil
. And since I don't care about
any state (the next value is readily apparent from the previous value we've
returned), that parameter in the returned function is named _
(the conventional name for ignored parameters). Since we initially gave
for
a nil value, that's what we get on the first call, so we
return false
. On the next call, value
is
false
so we return true
. On the third call, we
call through, returning nil
which ends the for
loop.
And those two functions make the test case generation code look much better. The intent is clearer, and you can easily match the code against the English description.
Saturday, January 24, 2015
Then again, Darth Vader was a whine baby growing up
How did the Galactic Empire ever cement its hold on the Star Wars Universe? The war machine built by Emperor Palpatine and run by Darth Vader is a spectacularly bad fighting force, as evidenced by all of the pieces of Death Star littering space. But of all the Empire's failures, none is a more spectacular military fiasco than the Battle of Hoth at the beginning of The Empire Strikes Back.
From a military perspective, Hoth should have been a total debacle for the Rebel Alliance. Overconfident that they can evade Imperial surveillance, they hole up on unforgiving frigid terrain at the far end of the cosmos. Huddled into the lone Echo Base are all their major players: politically crucial Princess Leia; ace pilot Han Solo; and their game- changer, Luke Skywalker, who isn't even a Jedi yet.
The defenses the Alliance constructed on Hoth could not be more favorable to Vader if the villain constructed them himself. The single Rebel base (!) is defended by a few artillery pieces on its north slope, protecting its main power generator. An ion cannon is its main anti- aircraft/spacecraft defense. Its outermost perimeter defense is an energy shield that can deflect Imperial laser bombardment. But the shield has two huge flaws: It can't stop an Imperial landing force from entering the atmosphere, and it can only open in a discrete place for a limited time so the Rebels' Ion Cannon can protect an evacuation. In essence, the Rebels built a shield that can't keep an invader out and complicates their own escape.
When Vader enters the Hoth System with the Imperial Fleet, he's holding a winning hand. What follows next is a reminder of two military truths that apply in our own time and in our own galaxy: Don't place unaccountable religious fanatics in wartime command, and never underestimate a hegemonic power's ability to miscalculate against an insurgency.
Via Jason Kottke, Inside the Battle of Hoth: The Empire Strikes Out | WIRED
Let's see … in “Star Wars,” a major design flaw in the Death Star lead to its destruction at the hands of a rooky fighter pilot in his first battle, and in “Return of the Jedi,” their second Death Star was destroyed by a rebel fleet after their only source of defense was taken out by ex-smuggler and a group of walking teddy bears.
And now this, the movie that supposedly shows the Empire at it's best.
Yeah, the Empire doesn't seem all that competent now.
Sunday, January 25, 2015
The Meow of HTTP status codes
If you were ever curious about the various status codes of HTTP, or if you like cats (or both!) then you might want to check out HTTP Status Cats (link via BoingBoing).
Monday, January 26, 2015
On napping
Ah, after work naps. How do I love thee? Let me count the ways …
- Zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
Tuesday, January 27, 2015
A fine line indeed
In C (and Lua, PHP, Python and just about
any other language you'll find on Unix), you use the function strftime()
to format a timestamp based on a format string. I
always have to look up the format when I want to use it, but hey, it's not
like I do it all the time (otherwise, I wouldn't have to look this up).
Anyway, it seems that Go is … different (of course! Rob Pike & Co. know better and feel that replacing the entire development chain is the way to go, what with mandating a coding style in the language design and a static-only linking technology straight from the 70s and its own runtime and standard library … but I digress), and I'm still trying to decide if the approach is stupid or clever—to specify the format with an example! (link to this via Hacker News).
const ( ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" RubyDate = "Mon Jan 02 15:04:05 -0700 2006" RFC822 = "02 Jan 06 15:04 MST" RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone RFC850 = "Monday, 02-Jan-06 15:04:05 MST" RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone RFC3339 = "2006-01-02T15:04:05Z07:00" RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" Kitchen = "3:04PM" // Handy time stamps. Stamp = "Jan _2 15:04:05" StampMilli = "Jan _2 15:04:05.000" StampMicro = "Jan _2 15:04:05.000000" StampNano = "Jan _2 15:04:05.000000000" )
Yes, you specify how you want the date formated by writing out January 2nd, 2006, at 3:05 PM in Mountain Standard Time (of course!) however you want it. Never mind that the 1-2-3 sequence is the American “month-then-day” format (Europe? Isn't that near New England somewhere? Across some pond or something).
Now, it's not the first language to specify output using an example. Some versions of Microsoft Basic had that feature to specify numeric output, but I've never seen anything quite like this.
And the justification for it?
I think the litmus test is that if a function's usage is so hard to remember that someone is motivated enough to create a domain and web site whose only purpose is to make it easier to remember where to find the documentation, then that function is broken. (http://strftime.org/)
Time.Format doesn't need to be the kitchen sink. If you need more control, there is always
fmt.Sprintf
. Unlike C'sstruct tm
, Go'stime.Time
does not require the addition of magic constants to turn struct fields into printable values.
Time formatting - Google Groups
I'm still unsure how I feel about this.
Wednesday, January 28, 2015
Those Compiler Warning Blues
It's always instructive to crank the warning level up on compilers. It
also helps to use different compilers since they tend to warn about
different things. With GCC, I use -Wall
(which
sadly, isn't all
possible warnings) but today I learned that clang (the default compiler on Mac OS-X
these days) has a -Weverything
option, so hey, why not try
it?
Wow!
It's not kidding—it warns about everything! Missing prototypes, gratuitous use of packed structures, added padding to structures, signed conversions (not only unsigned to signed, which I can see possibly losing information, but signed to unsigned, which doesn't), loss of interger precision, relying on auto-conversion of function calls (in my case, assigning the result of a function that returns a double to an unsigned long long variable), alignment changes in unions, even “default label in switch which covers all enumeration values.”
It's a lot of output to pour through. And this is for code that passes cleanly through GCC.
But in the ton of “legal, even if a bit questionable C” it still managed to find a real bug in my code:
In file included from common/XXXXlib.c:11:
third_party/uuid/src/uuid.h:34:17: warning: 'SHORT_MAX' is not defined, evaluates to 0 [-Wundef]
#if RAND_MAX == SHORT_MAX
^
It's a typo—it should be SHRT_MAX
(apparently, there was a
severe shortage of vowels in 70s computing, which is why C got stuck with a
bunch of vowel-impaired identifiers—sheesh!) but at the same time, it's
perfectly legal C, which is why I never noticed this until now.
The new video card, round two.
Last week, I initiated a return of the video card with Amazon. I stated my reason for returning it:
I received an ATI Technologies Inc RV370 [Radeon X300SE], which works, but is not what I ordered.
and I was informed that I should hear back from the third party company I ordered the video card from in less than 48 hours.
Nearly a week later, and I had yet to hear back.
I logged into Amazon to lodge another complaint when I stumbled across the message the third-party company sent to me (the following day, on the 21st), along with the error that prevented the email from being delivered:
Final-Recipient: rfc822; Sean Conner <sean@conman.org> Action: failed Diagnostic-Code: smtp; 554 4.4.7 Message expired: unable to deliver in 840 minutes.<450 <sean@conman.org>: Recipient address rejected: Service temporarily unavailable> Status: 4.4.7
XXXXXX! Amazon ran afoul of my greylisting daemon (Amazon is acting as a proxy between me and the third-party company—neither one of us has the other's true email address).
Checking the logs confirmed what I suspected happened: every attempt by Amazon to deliver the email came from a different IP address, which caused the greylist daemon to treat each attempt as a separate email and thus, block each attempt.
Sigh.
Once that was cleared up, I got the story as to what happened. The third-party company had run out of the video card I requested, and since the card they sent contained the same connectors and amount of memory, they felt it would be acceptable. Had I the right drivers, it might have been acceptable. But I didn't, so it won't.
The third-party company apologized for sending the wrong card. They also said they just received a new shipment of the video card I did order and they're sending one to me. All I need to do now is return the original card they sent back once I get the right card.
So … round three!
We shall see how this goes …
Loving County, Texas
… his phone rang with an old-fashioned warning: “You don't know it, but you're in trouble.” A group was planning a takeover of the county, said the caller, a woman in Arizona who promised to send him some information by e- mail. The material described the plans of a Libertarian faction in its own words “to win most of the elected offices in the county administration” and “restore to freedom” Loving County.
…
The goal, said an e-mail message attributed to a group member, was to move in enough Libertarians “to control the local government and remove oppressive regulations (such as planning and zoning, and building code requirements) and stop enforcement of laws prohibiting victimless acts among consenting adults such as dueling, gambling, incest, price-gouging, cannibalism and drug handling.”
…
Now pictures of the three decorate a poster on the sheriff's door at the Loving County Courthouse under the timeworn Wild West legend: “Wanted by the Texas Rangers.”
1 Cafe, 1 Gas Station and 2 Roads: America's Emptiest County
Oh real life! You are so much better than satire these days.
Thursday, January 29, 2015
A Software Archeological Approach to the First Video Game
At the Higham Institute sessions some months back, he and his friends had discussed the criteria for the ultimate display hack. Since they had been fans of trashy science fiction, particularly the space opera novels of E. E. “Doc” Smith, they somehow decided that the PDP-1 would be a perfect machine to make a combination grade-B movie and $120,000 [about $950,000 today —Editor] toy. A game in which two people could face each other in an outer-space showdown. …
Peter Samson, for instance, loved the idea of Spacewar, but could not abide the randomly generated dots that passed themselves off as the sky. Real space had stars in specific places. “We'll have the real thing,” Samson vowed. He obtained a thick atlas of the universe, and set about entering data into a routine he wrote that would generate the actual constellations visible to someone standing on the equator on a clear night. All stars down to the fifth magnitude were represented; Samson duplicated their relative brightness by controlling how often the computer lit the dot on the screen which represented the star. He also rigged the program so that, as the game progressed, the sky would majestically scroll at any one time the screen exposed 45 percent of the sky. Besides adding verisimilitude, this “Expensive Planetarium” program also gave rocket fighters a mappable background from which to gauge position. The game could truly be called, as Samson said, Shootout-at-El-Cassiopeia.
Another programmer named Dan Edwards was dissatisfied with the unanchored movement of the two dueling ships. It made the game merely a test of motor skills. He figured that adding a gravity factor would give the game a strategic component. So he programmed a central star a sun in the middle of the screen; you could use the sun's gravitational pull to give you speed as you circled it, but if you weren't careful and got too close, you'd be drawn into the sun. Which was certain death.
Before all the strategic implications of this variation could be employed, Shag Garetz, one of the Higham Institute trio, contributed a wild-card type of feature. He had read in Doc Smith's novels how space hot-rodders could suck themselves out of one galaxy and into another by virtue of a “hyper-spatial tube,” which would throw you into “that highly enigmatic Nth space.” So he added a “hyperspace” capability to the game, allowing a player to avoid a dire situation by pushing a panic button that would zip him to this hyperspace. You were allowed to go into hyperspace three times in the course of a game; the drawback was that you never knew where you might come out. Sometimes you'd reappear right next to the sun, just in time to see your ship hopelessly pulled to an untimely demise on the sun's surface. In tribute to Marvin Minsky's original hack, Garetz programmed the hyperspace feature so that a ship entering hyperspace would leave a “warp-induced photonic stress emission signature” a leftover smear of light in a shape that often formed in the aftermath of a Minskytron display.
The variations were endless. By switching a few parameters you could turn the game into “hydraulic Spacewar,” in which torpedoes flow out in ejaculatory streams instead of one by one. Or, as the night grew later and people became locked into interstellar mode, someone might shout, “Let's turn on the Winds of Space!” and someone would hack up a warping factor which would force players to make adjustments every time they moved. Though any improvement a hacker wished to make would be welcome, it was extremely bad form to make some weird change in the game unannounced. The effective social pressures which enforced the Hacker Ethic which urged hands-on for improvement, not damage prevented any instance of that kind of mischief. Anyway, the hackers were already engaged in a mind-boggling tweak of the system they were using an expensive computer to play the world's most glorified game!
Whenever I read Hackers, I was always wanted to play the version of Spacewar described and see the code. Sure, I had played the arcade version multiple times, and I even had a version of Spacewar for the IBM PC that I ran through a disassembler, printed the results and spent a summer going over the code (okay, this was back when I had the time to do such things, in high school) to see how it worked, but neither version sounded quite like the description in Hackers.
Now, thirty years later, computers are now fast enough that an emulator of the original Spacewar can be written in a scripting language and run on a web browser! Even better (well, for various values of “better”) is the extensive writeup about how Spacewar works, along with the actual source code (along with explanations of how one programs the PDP-1, a 5MHz 18-bit 1's complement machine with 4,096 18-bit words of memory.
My, how far we've come in 50 years.
Friday, January 30, 2015
Your surreal moment of the day
An abominable sight of monks (no, really!) chanting “Losing My Religion” (no, really!).
That is all.
Saturday, January 31, 2015
Some commentary about comments and commit messages
Whoever wrote line 4 of the following code snippet decided to access the
clientLeft
property of a DOM node for some reason, but do nothing with the result. It’s pretty mysterious. Can you tell why they did it, or is it safe to change or remove that call in the future?If someone pasted you this code, like I did here, you probably won’t be able to tell who wrote this line, what was their reasoning, and is it necessary to keep it. However, most of the time when working on a project you’ll have access to its history via version control systems.
Via Hacker News, Every line of code is always documented
At work, a former developer would always include a huge comment at the top of each file, describing the history of bug fixes to the code. It looked something like this:
//--------------------------------------------------------------------------- // // HISTORY OF CHANGE // // -----+--------+------------------------------------------+------+--------- // VERS | DATE | DESCRIPTION OF CHANGE | INIT | PR# // =====+========+==========================================+======+========= // 001 |06/09/05| File creation. | ABC | B1017 // -----+--------+------------------------------------------+------+--------- // 002 |06/24/07| Optimize the fob. | XYZ | B1130 // -----+--------+------------------------------------------+------+--------- // 003 |01/08/08| Make the fob more flexible. | XYZ | B0019 // -----+--------+------------------------------------------+------+--------- // 004 |04/15/09| The fob wasn't frobbing the widget. | XYZ | B0021 // -----+--------+------------------------------------------+------+--------- // 005 |02/02/10| Reduce the size of the gadget handler. | XYZ | B0005 // -----+--------+------------------------------------------+------+--------- // 006 |04/05/10| Work around Whatzat Protocol bug. | XYZ | B0024 // |04/14/10| Generalize the widget protocol. | | B0007 // -----+--------+------------------------------------------+------+--------- // 007 |01/20/10| Performance enhancement. | XYZ | B1019 // -----+--------+------------------------------------------+------+--------- // 008 |03/09/11| Race condition between hare and turtle. | XYZ | B1019 // |03/15/11| Beef up authentication. | | B1021 // -----+--------+------------------------------------------+------+---------
Seeing how we already use a version control system, which already contains this information and thus, there is no real need to put this in the source code itself, I asked him about it.
“Because not everyone has access to the version control server,” he said.
“What? Who can see the source code but does not have access to the version control server?” I asked.
“Customers we license the code to,” he said.
“But we don't license the code to anyone,” I said.
He then stormed off, saying I didn't understand how software was developed, but I think I see where he was coming from. He has a side-company where he licenses the source code to his products and didn't want his customers to have access to his version control server. Adding this information to the files themselves let his customers know what has been fixed. But he kept the practice up at The Corporation because that's the way he's always done it. It made sense for his company, but not for The Corporation. We aren't going to license this code to anyone, and anyone that is working on it has access to the version control server and can see the entire history of any of the files in the project.
But that's not to say that all commentary about the code should go exclusively in version control. The history of bug fixes, yes, that can go into version control as there's no need to clutter up the source code files with that information. But comments that describe why the code is doing something odd should go in the file itself, above the odd bit of code.
For example, in my own blogging engine, I have this commit:
commit eab6ecb7149f8b70614657cd20fe09337cf5e977 Author: Sean Conner <spc@conman.org> Date: Tue Jan 15 23:43:19 2013 -0500 Bug fix---tumbler problems, but not necessarily with the parsing The intent was if the start date was later than the end date, swap the two dates and set the reverse flag. Unfortunately, the logic to determine the swap was wrong. Wong wrong wrong wrong wrong. I moved the check down, and rewrote the check logic. It should be fine now, but get back to me in another decade.
But the code that handles this is a bit odd (it was even worse before I fixed it) so I added a comment to the modified code:
/*------------------------------------------------------------------------ ; swap tumblers if required. If the parts are the default values, swap ; them, as they probably weren't specified and need swapping as well. ; ; Example: ; ; 2000/02/04 - 01/26 ; -> 2000/02/04.1 - 2000/01/26.23 ; -> 2000/01/26.23 - 2000/02/04.1 ; -> 2000/01/26.1 - 2000/02/04.23 ; ;-----------------------------------------------------------------------*/ if (btm_cmp(&start,&end) > 0) { struct btm tmp; gd.f.reverse = true; tmp = start; start = end; end = tmp; if ((start.part == 23) && (end.part == 1)) { start.part = 1; end.part = 23; } } }
The comment describes what the code is doing (and shows an example; I'll admit, the comment could be a bit better). But notice how the commit describes why I made the change—it's a comment on the comment as it were.
Sunday, February 01, 2015
The Jedi sure are manipulative bastards
At the end of Episode III, there are two new babies who are down two viable parents—mom's died of a broken heart (or something) and dad has become a tyrannical right hand to the galaxy's freshly minted dictator. They need homes but, more importantly, they need to be kept safe from interfering influence. Most of the Jedi have been wiped out, and resistance to the Empire is a bad bet when it's on its way in; Palpatine has too many resources, he planned his takeover too carefully.
Yoda and Obi-Wan knew all this coming out of the Clone Wars. They knew that even with the handful of Jedi who survived the Purge at their disposal, they had no chance of taking on the new regime. It was better to let Palpatine get comfortable, to hide away and await a better opening. And considering the power that both Vader and the Emperor could claim mastery over, using Anakin's kids were a good bet; after all, their dad was literally conceived out of raw Force trail mix and some of Shmi Skywalker's genetics. They were bound to have similar power at their disposal, the better to knock off dear old dad with.
Here's the problem with children—they grow up to be fully realized human beings. The Jedi knew what they were doing, taking infants from their parents to indoctrinate them into the old Order. Initiating kids before they could talk, becoming their true family, resulted in “better” Jedi. (Translation: Jedi who do as they're told by the Jedi Council and their mentors.) But Anakin's children were better off being raised out of contact with Jedi. That way, if someone managed to locate Yoda or Obi-Wan, the Only Hopes of the galaxy remained safe and secret.
Via MyFaceGooglePlusSpaceBook, This is Why Obi-Wan Lied to Luke Skywalker About His Father | Tor.com
It's a long article, but it does seem to explain why Obi-Wan outright lied to Luke about his parentage. I never expected the Good Guys to lie, but the Bad Guys? Yeah, I expect them to lie to get ahead, that's what Bad Guys do!
But not the Good Guys! The Good Guys don't manipulate people, don't lie, fight fair, and above all, never act like a vigilante.
Um … are we sure the Empire aren't the good guys? Yeah, they're incompetent, but really? The Bad Guys?
Monday, February 02, 2015
The smallest chess program ever written
Thirty-two years ago, David Horne wrote a chess program for the ZX-81. It didn't play a great game of chess, and you can't castle, capture en passant nor promote a pawn, but it did have one redeeming feature that set it above every other chess program—it took less than 1K of space! The program, in its entirety, is only 672 bytes in size.
But there's a new contender for the smallest chess game (and the same limitations—no castling, no en passant, no promotion) with BootChess, which is an incredible 487 bytes in size!
Even a program of a single instruction can have bugs
The previous entry reminded of the following computer joke:
Every program has at least one bug and can be shortened by at least one instruction—from which, by induction, one can deduce that every program can be reduced to one instruction which doesn't work.
Only it's not a joke—it really happened!
Tuesday, February 03, 2015
And I still haven't found what I'm looking for
If I have any text processing to do, I pretty much gravitate towards using LPeg. Sure, it might take a bit longer to generate code to parse some text, but it tends to be less “write only” than regular expressions.
Besides, you can do some pretty cool things with it. I have some LPeg code
that will parse the following strftime()
format string:
%A, %d %B %Y @ %H:%M:%S
and generate LPeg code that will parse:
Tuesday, 03 February 2015 @ 20:59:51
into:
date = { min = 57.000000, wday = 4.000000, day = 4.000000, month = 2.000000, sec = 16.000000, hour = 20.000000, year = 2015.000000, }
Or, if I set my locale correctly, I can turn this:
maŋŋebarga, 03 guovvamánu 2015 @ 21:00:21
into:
date = { min = 0,000000, wday = 3,000000, day = 3,000000, month = 2,000000, sec = 21,000000, hour = 21,000000, year = 2015,000000, }
But one annoyance that hits from time to time—named captures require a constant name. For instance, this pattern:
pattern = lpeg.Ct( lpeg.Cg(lpeg.P "A"^1,"class_a") * lpeg.P":" * lpeg.Cg(lpeg.P "B"^1,"class_b") )
(translated: when matching a string like AAAA:BBB
, return a
Lua
table (lpeg.Ct()
) with the As (lpeg.P()
) in
field class_a
(lpeg.Cg()
) and the Bs in field
class_b
)
applied to this string:
AAAA:BBB
returns this table:
{ class_a = "AAAA", class_b = "BBB }
The field names are constant—class_a
and
class_b
. I'd like a field name based on the input. Now, there is
a function lpeg.Cb()
that is described as:
Creates a back capture. This pattern matches the empty string and produces the values produced by the most recent group capture named
name
.Most recent means the last complete outermost group capture with the given name. A Complete capture means that the entire pattern corresponding to the capture has matched. An Outermost capture means that the capture is not inside another complete capture.
LPeg - Parsing Expression Grammars For Lua
A quick reading (and I'm guilty of this) leads me to think this:
pattern = lpeg.Cg(P"A"^1,"name") * lpeg.P":" * lpeg.Ct(lpeg.P "B"^1,lpeg.Cb("name"))
applied to the string:
AAAA:BBB
returns
{ AAAA = "BBB" }
But sadly, no. The only example of lpeg.Cb()
, used to parse
Lua long strings (which start with a “[”, zero or more “=”, another “[”, then
text, ended with a “]”, zero or more “=” (but the number of “=” must equal
the number of “=” between the two “[”) and a final “]”)):
equals = lpeg.P"="^0 open = "[" * lpeg.Cg(equals, "init") * "[" * lpeg.P"\n"^-1 close = "]" * lpeg.C(equals) * "]" closeeq = lpeg.Cmt(close * lpeg.Cb("init"), function (s, i, a, b) return a == b end) string = open * lpeg.C((lpeg.P(1) - closeeq)^0) * close / 1
shows that lpeg.Cb()
was designed with this partular use case
in mind—matching one pattern with the same pattern later on, and not what I
want.
I can do what I want (a field name based upon the input) but the way to go about it is very klunky (in my opinion):
pattern = lpeg.Cf( lpeg.Ct("") * lpeg.Cg( lpeg.C(lpeg.P"A"^1) * lpeg.P":" * lpeg.C(lpeg.P"B"^1) ) ,function(acc,name,value) acc[name] = value return acc end )
This is a “folding capture” (lpeg.Cf()
) where we
are accumulating our results (even though it's only one result—we have to do
it this way) in a table (lpeg.Ct()
) where each “value” is a
group (lpeg.Cg()
—the name is optional) consisting of a
collection (lpeg.C()
of As (lpeg.P()
) followed by a
colon (ignored), followed by a collection of Bs, all of which (except for the
colon—remember, it's ignored) are passed to a function that assigns the
string of Bs to a field name based on the string of As.
It gets even messier when you mix fixed field names with ones based upon the input. If all the field names are defined, it's easy to do something like:
eoln = P"\n" -- match end of line text = (P(1) - eoln)0 -- match anything but an end of line pattern = lpeg.Ct( P"field_one: " * Cg(text^0,"field_one") * eoln * P"field_two: " * Cg(text^0,"field_two") * eoln * P"field_three:" * Cg(text^0,"field_three") * eoln )
against data like this:
field_one: Lorem ipsum dolor sit amet field_two: consectetur adipiscing elit field_three: Cras aliquet enim elit
to get this:
{ field_one = "Lorem ipsum dolor sit amet", field_two = "consectetur adipiscing elit", field_three = "Cras aliquet enim elit" }
But if we have some defined fields, but want to accept non-defined field names, then … well … yeah … I haven't found a nice way of doing it. And I find it annoying that I haven't found what I'm looking for.
Wednesday, February 04, 2015
A silly little file redirection trick under Unix
I'm in the process of writing a regression test for “Project: Sippy-Cup” and right now I'm more concentrating on writing what I call a “smoke-test”—something that can be run on my development machine after fixing bugs or adding features so that any obvious problems are “smoked out” before it hits the version control system.
Like “Project: Wolowizard,” this involves running multiple components. That isn't that much of an issue, I have plenty of Lua code to launch a program, and it typically looks like:
errno = require "org.conman.errno" syslog = require "org.conman.syslog" process = require "org.conman.process" pid,err = process.fork() if not pid then syslog('error',"fork() = %s",errno[err]) os.exit(process.EXIT.SOFTWARE) -- who knew about /usr/include/sysexits.h? elseif pid == 0 -- child process local stdin = io.open("/dev/null","r") local stdout = io.open("foobar.stdout.txt","w") local stderr = io.open("foobar.stderr.txt","w") -- -------------------------------------------------------------------- -- redirect stdin, stdout and stderr to these files. Once we've done -- the redirection, we can close the files---they're still "open" as -- stdin, stdout and stderr. Then we attempt to start the program. If -- that fails, there's not much we can do, so just exit the child -- process at that point. -- -------------------------------------------------------------------- fsys.dup(stdin,fsys.STDIN) fsys.dup(stdout,fsys.STDOUT) fsys.dup(stderr,fsys.STDERR) stderr:close() stdout:close() stdin:close() process.exec(EXE,{ "–config" , "config.xml" }) process.exit(process.EXIT.SOFTWARE) end
Each program is launched in a similar manner, and if any of them crash,
the testing harness gets notified. Also, once the tests are done, I can
shutdown each process cleanly, all under program control. I want this to be
a simple run-me
type command that does everything.
During the testing of the testing program, it is nice to be able
to see the output of the programs being tested. Sure, I have any output
from the programs going to a file, but the problem with that is that it's
hard to watch the output in real time. Upon startup (at least under Unix)
if stdout
(the normal output stream) is a terminal, the output
appears a line at a time; otherwise, the output is “fully
buffered”—meaning it's only actually written when there's around 4K or 8K
worth of output, and if the programs aren't that chatty, you could be
waiting a while if you're constantly checking the output files.
But there is a trick—this being Unix, you can redirect the
output to another terminal (or in this modern age, a terminal window). I
open up a spare terminal window (it's easy enough), and run the
w
command to find its device entry:
[spc]lucy:~>w 20:31:32 up 15 days, 6 min, 3 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT spc pts/0 marvin.roswell.a 20:06 17.00s 0.28s 0.27s joe 2 spc pts/1 marvin.roswell.a 20:15 15:50 0.03s 0.02s vi process.c spc pts/2 marvin.roswell.a 20:31 0.00s 0.01s 0.00s w [spc]lucy:~>
Here, I can see that the w
command is being run on terminal
device /dev/pts/2
(under Linux, the “/dev/” portion isn't
listed). So all I need to do is redirect stdout
and
stderr
to /dev/pts/2
and the output will appear in
that window, in real time.
So why do it in this roundabout way? Well, remember, I have several programs running. By opening up multiple terminal windows and directing the output of each program to these windows, the output from each program is kept separated and I can see what's going on. Then, when the testing program is working, I can then go back to writing the output to a file.
Oh, and under Mac OS-X:
spc]marvin:~>w
20:40 up 21 days, 1:20, 8 users, load averages: 0.01 0.05 0.08
USER TTY FROM LOGIN@ IDLE WHAT
spc console - 14Jan15 21days -
spc s000 - 18:48 32 -ssh XXXXXXXXXXXXXXXXXX
spc s001 - 20:07 23 -bash
spc s002 - 14Jan15 21days syslogintr
spc s003 - 20:07 - w
spc s004 - 20:07 - -ssh lucy
spc s005 - 20:16 7 -ssh lucy
spc s006 - 20:32 - -ssh lucy
[spc]marvin:~>
The “s003” now becomes /dev/ttys003
.
Of course, statistics has little to say about Murphy's Law
Everyone knew it was coming. Second-and-1 on the 1-yard line. Marshawn Lynch was waiting in the backfield, poised to do what he was put on this Earth to do: Get a touchdown—this touchdown. The football gods had telegraphed how they wanted the game to end, directing a floating ball straight into Jermaine Kearse's hands. Beast Mode was going to drag the New England team kicking and screaming into the end zone if he had to. But the play call came in, Russell Wilson attempted a doomed pass that Malcolm Butler intercepted, and it was Seattle that punched and screamed its way off the field.
…
That's right. On the 1-yard line, QBs threw 66 touchdowns with no interceptions prior to Wilson's errant toss.3 Not mentioned: They also scored four touchdowns on scrambles (which Wilson is pretty good at last I checked). That's a 60.9 percent success rate.
Just for comparison's sake, here's how more than 200 runs fared this year in the same situation:
- 125 led to touchdowns.
- 94 failed to score.
- Of those, 23 were for loss of yardage.
- Two resulted in lost fumbles.
So overall, runs do a bit worse than passes (57.1 percent vs. 60.9 percent).
Via Robert Anstett on MyFaceGooglePlusSpaceBook, A Head Coach Botched The End Of The Super Bowl, And It Wasn’t Pete Carroll | FiveThirtyEight
I don't watch much football (if at all), but even I knew that last Seahawks play was not the right call. But actually, it may not have been the most idiotic thing for the Seahawks to do. The article goes deep into the math behind Pete Carroll's call.
Thursday, February 05, 2015
Bug hunt
Today T, a fellow cow-order here at The Ft. Lauderdale Office of The Corporation, found a particularly nasty bug in “Project: Sippy-Cup”—two identical SIP packets caused the request to fail. It uses UDP for the network transport, so duplicate packets are a possibility (so are dropped packets, but that's already being handled properly), something that the code didn't handle properly.
Now, “Project: Sippy-Cup” is written in Lua. I only say this because of how I handle
requests. The main loop of the program waits for network packets using
poll()
(or epoll_wait()
if running
under Linux; they're like calls to select()
(which is all you ever see in Unix networking tutorials because everybody is
basing the code off examples written in the early 90s but I digress) only
less CPU intensive).
When poll()
returns, I either create a coroutine or resume a
coroutine (depending on where we are in the request) to handle the
request.
I did it this way, even though I have to manually switch coroutines, to make the processing of requests easier to follow:
function handle(request) if not validate(request) socket:send(request.sender,"400 Bad client! No cookie for you!") return end socket:send(request.sender,"200 Good boy! You're such a good boy!") local info = lookup_details(request) -- blocking call local contact = dns.lookup(request.contact) -- blocking call socket:send(contact,info) local reply = socket:recv() -- blocking call if not reply.okay then log("I messed up") end end
rather than having all this logic spread across multiple functions where each function represents a step in the processing:
-- not shown, the code that receives packets and calls the appropriate -- routine. function handle_incoming(state) if not validate(state.request) socket:send(state.request.sender,"400 Bad client! No cookie for you!") return end socket:send(state.request.sender,"200 Good boy! You're such a good boy!") return lookup_details -- next function to call end function lookup_details(state) state.info = -- code to send request return contact_dns end function contact_dns(state) state.contact = state.request.contact -- code to send a DNS request return got_dns_response end function got_dns_response socket:send(state.contact,state.info) return process_reply end function process_reply(state) if not state.reply.okay then log("I messed up") end end
It's fairly straightforward—once I get a SIP packet, I check a list to see if I've already created a coroutine based on the unique ID included in the packet. If one does exist, I then resume that coroutine; otherwise, I create one. The coroutine will run until it either finishes, or a function will block (say, a DNS query), and the code that could block will add the coroutine to a list it maintains and yield back to the main code.
The main coroutine, at 50,000 feet:
poll()
returns.- It's a SIP packet: process it:
- Get the unique ID from the SIP packet.
- Use the ID to check the list of SIP coroutines. If a coroutine does not exist, create one and add it to the list.
- Resume the coroutine.
- If the coroutine has ended, remove the reference from the list of SIP coroutines; otherwise
- The coroutine has called
coroutine.yield()
, so keep the reference arond.
- It's another type of packet (see below)
- Go back to step 1.
Any routine that might block (and they're all network related) will put
the coroutine on a list, and yield. So, when call
dns.lookup()
, that function does:
- Do have have the data cached? If so, return it.
- Otherwise, create the DNS request.
- Send the DNS request to a DNS server.
- Place the coroutine on a DNS list, indexed with the DNS request ID.
- Call
coroutine.yield()
, which returns us to the main loop. - We resume here, so remove the coroutine from the DNS list.
- Cache the data.
- Return the data.
So, step 3 of the main coroutine contains these sub-steps:
- Get the unique ID from the DNS packet.
- Get the coroutine from the DNS list, indexed by the ID.
- Resume that coroutine.
The lookup_detail()
function (the handling of which would be
step 4, which isn't shown) is similar to the DNS lookup. This all works and while the main driver
code is a bit complex (and the complexity has to live somewhere),
the actual processing code is nice and linear, making it easier to change
the “business logic” in one place rather than have it scattered throughout
the codebase.
Now we get to the bug—mishandling of duplicate packets. The first
SIP packet comes in,
has a unique ID, so a coroutine is created, we get to the call to
lookup_details()
and we yield, waiting for a reponse from our
database engine (not a real database engine, but close enough). The
duplicate SIP packet
comes in. We already have a coroutine associated with this SIP ID, so re blindly resume
it. The coroutine, freshly resumed, assumes the reply from the database has
arrived and things go down hill from there (but only for that request; the
program is still running and can handle new requests).
The solution is to realize we have a duplicate request and not resume the coroutine in that case.
And like most bugs, the fix is trivial—it's the hunt that's difficult.
Friday, February 06, 2015
The new video card, round three
The replacement replacement video card finally arrived! Woot!
The good: It's the right card!
The bad: It was not going into graphics mode when I run X.
The ugly: It took a few hours, but I finally got it working. It seems that when I tried the previous video card, the configuration was overwritten, and it took some gentle persuasion with a large hammer to straighten it out.
So now it's time to send back the wrong card, and relax now that this adventure is over.
Do not disturb the Happy Fun Sean
What I thought was going to be a very simple operation of “take the old video card out, put the new video card in and we're good to go” wasn't. And as typical of when one problem leads to another problem which leads to yet another problem, I get very focused while at the same time I get extremely angry. As the issues pile up, as I'm reading scores of web pages with conflicting information (that is, when they have an answer out of the hundreds of pages checked) and I'm building up this huge fragile structure in my mind of everything I've tried, what I've yet to try, and futher questions to answer—
“What would you like for lunch?”
And it collapses like a house of cards, leaving me to start all over again.
I'll admit, it can be hard to distinguish between this and “very focused while working in a program” just prior to the house of cards collapse, but my response in the former is a primal scream while the my reponse to the later requires scraping me off the ceiling.
Bunny has learned to live with it.
The Alton Brown Edible and Inevitable Tour
Yeast.
The preshow consists of sock puppets of belching yeast.
And farts. Sock puppets of belching and farting yeast.
In time to the Alfred Hitchcock Theme.
Of course it can only mean one thing—Bunny and I had tickets to the Alton Brown Edible Inevitable Tour!
Alton was nice enough to take our picture and post it to Twitter.
My god—what a show!
Alton Brown is extremely funny. After an attempt at rapping (he should not quit his day job, that's all I have to say about that), he went into “Things He Could Not Say On Televsion” which include rants against chicken fingers (“when I am depressed, or sad, or even bored, I just have to remember the sound of little girls screaming … ”) to trout ice cream.
He makes a gallon of chocolate ice cream in 10 seconds (and it does not involve liquid nitrogen) and using the worlds largest Easy•Bake Oven (cranked to 11, it can be seen from outer space) he cooks pizza in four minutes.
And I best not forget his country song to Airline Lounge Shimp Cocktail. Rapping aside, he's not that bad of a singer and I've certainly heard worse.
All I can say is, if you are a fan of Good Eats or of Alton Brown in general, you should go. It's easily worth the ticket price.
And yes, he always carries nutmeg in his pocket.
Saturday, February 07, 2015
The VC model to R&D
There's a fascinating article about Xerox PARC (link via Hacker News) and how Xerox dropped the ball on computing (only to have Apple pick up the ball and run with it, followed closely by Microsoft).
But what most people don't realize is that Xerox was never in the computer business, and I think licensing the technology to Apple was probably a smart move. But to me, this is the key quote:
“Xerox did research outside their business model, and when you do that you should not be surprised that you have a hard time dealing with it—any more than if some bright guy at Pfizer wrote a word processor. Good luck to Pfizer getting into the word-processing business. Meanwhile, the thing that they invented that was similar to their own business—a really big machine that spit paper out—they made a lot of money on it.” And so they did. Gary Starkweather’s laser printer made billions for Xerox. It paid for every other single project at Xerox PARC, many times over.
Creation Myth - The New Yorker
That quote, “[i]t paid for every other single project at Xerox PARC, many times over,” is, to me, the key quote as to why large companies should always invest in research and development. Sure, not every idea will pan out, but those that do pan out, really pan out! (Heck, venture capitalists do that today—fund a bunch of projects, most of which will fail, but the ones that don't make tons of money)
Sunday, February 08, 2015
As if a ½K Chess program wasn't hardcore enough
These next few posts are a technical write-up of how I created 8088 Domination, which is a program that displays fairly decent full-motion video on a 1981 IBM PC.
Via Hacker News, 8088 Domination Post-Mortem, Part 1 « Oldskooler Ramblings
Yes, a 4.77MHz 8088 based computer with an effective harddrive transfer rate of 90KB/s can do full motion video.
Okay, it's not a great video image, but still, it's an impressive display of coding expertise and thinking outside of the box.
Monday, February 09, 2015
I just kind of wish Lua could catch these types of bugs automatically like a C compiler can
Another day, another bug in “Project: Sippy-Cup.” This time a simple typo, the type of typo that a compiler would have caught before the code was checked in. And it's the type of bug that is the most prevalent in my code.
I'm beginning to see why unit testing is so popular with the scripting/dynamic languages—they catch the types of bugs that compilers of static languages already catch.
On the down side, unit testing ensures that I get to play “compiler” far more often than I care to …
Sigh.
Tuesday, February 10, 2015
I wonder if anyone has read 100 Years of Solitude 100 times?
I have read two books more than a 100 times, for different motives and with different consequences. Hamlet I read a 100 times for my dissertation, The Inimitable Jeeves by PG Wodehouse a 100 times for comfort. The experience is distinct from all other kinds of reading. I’m calling it centireading.
I read Hamlet a 100 times because of Anthony Hopkins. He once mentioned, in an interview with Backstage magazine, that he typically reads his scripts over a 100 times, which gives him “a tremendous sense of ease and the power of confidence” over the material. I was writing a good chunk of my doctoral dissertation on Hamlet and I needed all the sense of ease and power of confidence I could muster.
…
It’s not necessarily the quality. The Inimitable Jeeves does not contain the best Wodehouse story. That is either Lord Emsworth and the Girl Friend, which Rudyard Kipling called “the perfect short story” or Uncle Fred Flits By collected in Young Men in Spats. But there are no dull moments in The Inimitable Jeeves, no bad parts. Each plot is a novelty, without a trace of laziness. There is not a single weak verb in the entire book.
Via Hacker News, Centireading force: why reading a book 100 times is a great idea | Books | The Guardian
Interesting. I wonder what my friend Hoade would have to say about this?
For me, I don't think I've read any book a hundred times, although I might be in the upper two digits for a few books.
One book I've read so many times my copy is falling apart is Hackers: Heros of the Computer Revolution. It's about three groups of iconic programmers, the MIT graduate students in the 60s (Green blatt, Gosper, Tom Knight, etc.); the Homebrew Computer Club group from the 70s (Woz, Felsenstein, Captain Crunch, etc.), and the scores of teenagers banging out computer video games in the 80s (John Harris—all of this is from memory and I'll stop now before I post the entire book from memory). I can certainly say it had an effect on me and heavily influenced my views on programming.
Another book I've read dozens of times is Have Space Suit, Will Travel, the first science fiction book I read (so it's heavy with nostalgia), and one that doomed me to reading science fiction almost exclusively. My favorite part of the book is when Kip (the main protagonist) is imprisoned on Pluto and he spends his time figuring out how fast he travelled to Pluto by knowing both the time (five days) and distance (30 AU), while upset that he doesn't have his slipstick to help with the calculations (and I now have a few slipsticks of my own because of this book).
I'm not sure what that says about me, though.
Another book I've read uncountable times is Snow Crash, a wild science-fiction cyberpunk romp of the near future where the United States Government is just another franchise, and the main villain is a cross between H. Ross Perot and L. Ron Hubbard whose hired hand, an Aleut harpoonist, has been declared a sovereign nation unto himself (for he has his own tactical nuclear weapon).
Yes, it sounds insane describing it, but it is really good, really funny, and again, I'm not sure what it says about me that my favorite bits are the exposition-heavy bits about neurolinguistic hacking.
There aren't many other books I've read quite as often as those, but if you include comic books, then there are about a dozen or so Uncle Scrooge comic books I probably have read a hundred times or so …
Wednesday, February 11, 2015
So if we “do it like they do on the Discovery Channel,” does that mean they “do it like we do on Reefer Madness?”
Noah’s Ark, he found, would have looked a lot like London on a Saturday night. “In every country, in almost every class of animal,” Siegel explains, “I found examples of not only the accidental but the intentional use of drugs.” In West Bengal, a group of 150 elephants smashed their way into a warehouse and drank a massive amount of moonshine. They got so drunk they went on a rampage and killed five people, as well as demolishing seven concrete buildings. If you give hash to male mice, they become horny and seek out females — but then they find “they can barely crawl over the females, let alone mount them,” so after a little while they yawn and start licking their own penises.
In Vietnam, the water buffalo have always shunned the local opium plants. They don’t like them. But when the American bombs started to fall all around them during the war, the buffalo left their normal grazing grounds, broke into the opium fields, and began to chew. They would then look a little dizzy and dulled. When they were traumatized, it seems, they wanted — like the mongoose, like us — to escape from their thoughts.
Via Hacker News, Why animals eat psychoactive plants - Boing Boing
Posted mostly for a few friends who shall remain nameless who might find this article interesting.
You know who you are.
Thursday, February 12, 2015
Sixteen hours to change three lines of code
The bug report was simple enough: “Project: Sippy-Cup” would, when it had to retransmit the data (remember, we're running over UDP), it would send an additional packet.
Sippy Cup | direction | Client |
---|---|---|
DATA | → | (packet dropped) |
DATA | → | (packet received) |
(packet recieved) | ← | ACK |
DATA | → |
So far, the bugs found in “Project: Sippy-Cup” have been easy to reproduce (thankfully!) and easy to fix once identified. This one was easy to reproduce … and took two days of intense effort to fix. The bug is not a show-stopper, and the client should (there's that word) handle the duplicate packet. My manager, S, was subtly hinting that I should put this on the backburner, but this is one of those problems that just irks me.
I added logging statements. I instrumented the code. I traced the
execution of the program line-by-line (easy enough to do within Lua as there's a pre-defined
method for hooking into the execution engine, and even though this didn't
reveal the root cause of the bug, it did reveal a few places where
some simple changes optimized the code (but that's for another post). For
example, here's all the code that's
executed when you run the luarocks
command, but fair
warning—it's nearly 7,000 lines long) and it became clear that
something was wrong with the timeout handling (what I didn't
mention the other day about scheduling
coroutines is how I handle timeouts, but alas, that's for another post
as well). The code is basically:
request = receive_packet_from_client() send_ack() send_request_to_db(request) -- ------------------------------------------------------------------ -- This sets things up to force the coroutine to resume in one second, -- returning a result of nil. -- ------------------------------------------------------------------ timeout(1) -- ---------------------------------------------------------------- -- the code that resumes this coroutine will pass in the result in -- coroutine.resume(), which is assigned to dbresult -- ---------------------------------------------------------------- dbresult = coroutine.yield() -- ------------------------------------------------------------------------ -- cancel a pending timeout, if any. If we did timeout, this is a NOP. If -- we haven't timed out, this prevents the timeout from triggering. -- ------------------------------------------------------------------------ timeout(0) if not dbresult then info = failed() else info = extract(dbresult) end for retries = 1 , 3 do send_information_to_client() timeout(1) ack = coroutine.yield() timeout(0) if ack then return end end
I was able to determine that the initial “timeout” was the request to the database engine timeout trigger (after hacking in a way to track the timeout requests) which meant the timeout code wasn't working properly. Once that was clear, I was able to locate the problem code:
-- ------------------------------------------------------------------------ -- TQUEUE contains references to coroutines that want a timeout. If we set -- the timeout to 0, this just sets the awake field to 0, which informs the -- coroutine scheduler not to run the coroutine when it "times out". -- ------------------------------------------------------------------------ function timeout(when) local f = coroutine.running() if when == 0 then if TQUEUE[co] then TQUEUE[co].awake = 0 -- oops, bug. See this post for details end else TQUEUE:insert(when,f) end end
Here we have an instance where a
static compiler would have flagged this immediately. I either need to
rename f
to co
, or change co
to
f
. A simple two line fix (and I really need to find a
code checker for Lua).
The other issue, now quickly found, was this bit of code:
local function handler(info,err,remote,message,startime) ... local ninfo,err,nremote,nmessage = coroutine.yield() timeout(0) if err == 0 then if not message.request.status then -- error else return nmessage end else ...
Even a static compiler would not have found this issue—I was checking the wrong variable! The code should read:
if not nmessage.request.status then
Bad me for using a bad name for a variable. No cookie for me!
Okay, this is a simple one line change. Total lines changed: 3.
Friday, February 13, 2015
A missed optimization in Lua
Yesterday, I made brief mention of optimizing some Lua code, and said it was for another post.
This is said post.
The code in question (not identical, but this exhibits the same problem):
require "ddt".tron() -- trace the execution local lpeg = require "lpeg" local Cs = lpeg.Cs local C = lpeg.C local R = lpeg.R local P = lpeg.P function canonical(header) local function Pi(text) local pattern = P(true) for c in text:gmatch(".") do pattern = pattern * (P(c:lower()) + P(c:upper())) end return pattern / text end local ALPHA = R("AZ","az") local id = Pi "ID" -- exceptions to Camel-Case + Pi "MIME" + Pi "CSeq" local word = (C(ALPHA) * C(ALPHA^0)) / function(i,r) return i:upper() .. r:lower() end local other = C((P(1) - ALPHA)^1) local hdr = Cs((id + word + other)^1) return hdr:match(header) end print(canonical "return-from") print(canonical "message-id") print(canonical "mime-version") print(canonical "cseq")
The code in question transforms a header name like
return-from
to the canonical form Return-From
;
it'll also transform ReTuRn-FRom
into the canonical form. The
code is used to match headers in Internet based messages like email,
HTTP or SIP (as the header names need
to match case-insensitively—I'll leave how it works to you, the reader (here are
some hints) since what the code does isn't germane to this discussion).
Now, when you trace the execution, you'll notice something:
@./ddt.lua 187: end @code.lua 2: local lpeg = require "lpeg" @code.lua 4: local Cs = lpeg.Cs @code.lua 5: local C = lpeg.C @code.lua 6: local R = lpeg.R @code.lua 7: local P = lpeg.P @code.lua 34: end @code.lua 9: function canonical(header) @code.lua 36: print(canonical "return-from") @code.lua 18: end @code.lua 20: local ALPHA = R("AZ","az") @code.lua 22: local id = Pi "ID" -- exceptions to Camel-Case @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 23: + Pi "MIME" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 24: + Pi "CSeq" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 26: local word = (C(ALPHA) * C(ALPHA^0)) @code.lua 29: end @code.lua 30: local other = C((P(1) - ALPHA)^1) @code.lua 31: local hdr = Cs((id + word + other)^1) @code.lua 33: return hdr:match(header) @code.lua 28: return i:upper() .. r:lower() @code.lua 28: return i:upper() .. r:lower() @code.lua 37: print(canonical "message-id") @code.lua 18: end @code.lua 20: local ALPHA = R("AZ","az") @code.lua 22: local id = Pi "ID" -- exceptions to Camel-Case @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 23: + Pi "MIME" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 24: + Pi "CSeq" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 26: local word = (C(ALPHA) * C(ALPHA^0)) @code.lua 29: end @code.lua 30: local other = C((P(1) - ALPHA)^1) @code.lua 31: local hdr = Cs((id + word + other)^1) @code.lua 33: return hdr:match(header) @code.lua 28: return i:upper() .. r:lower() @code.lua 38: print(canonical "mime-version") @code.lua 18: end @code.lua 20: local ALPHA = R("AZ","az") @code.lua 22: local id = Pi "ID" -- exceptions to Camel-Case @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 23: + Pi "MIME" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 24: + Pi "CSeq" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 26: local word = (C(ALPHA) * C(ALPHA^0)) @code.lua 29: end @code.lua 30: local other = C((P(1) - ALPHA)^1) @code.lua 31: local hdr = Cs((id + word + other)^1) @code.lua 33: return hdr:match(header) @code.lua 28: return i:upper() .. r:lower() @code.lua 39: print(canonical "cseq") @code.lua 18: end @code.lua 20: local ALPHA = R("AZ","az") @code.lua 22: local id = Pi "ID" -- exceptions to Camel-Case @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 23: + Pi "MIME" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 24: + Pi "CSeq" @code.lua 12: local pattern = P(true) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @code.lua 13: for c in text:gmatch(".") do @code.lua 17: return pattern / text @code.lua 26: local word = (C(ALPHA) * C(ALPHA^0)) @code.lua 29: end @code.lua 30: local other = C((P(1) - ALPHA)^1) @code.lua 31: local hdr = Cs((id + word + other)^1) @code.lua 33: return hdr:match(header)
There's quite a bit of code executed. That's because the Lua compiler
isn't sufficiently
smart to notice that most of the code in canonical()
never changes—it's independent of the passed in parameter and
thus, it could be compiled once. And it's this behavior that I noticed the
other day. It's an easy fix (just lift the invarient code out of the
function body) and the results are about a third the processing:
@./ddt.lua 187: end @c3.lua 2: local lpeg = require "lpeg" @c3.lua 4: local Cs = lpeg.Cs @c3.lua 5: local C = lpeg.C @c3.lua 6: local R = lpeg.R @c3.lua 7: local P = lpeg.P @c3.lua 18: end @c3.lua 20: local ALPHA = R("AZ","az") @c3.lua 22: local id = Pi "ID" -- exceptions to Camel-Case @c3.lua 12: local pattern = P(true) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 17: return pattern / text @c3.lua 23: + Pi "MIME" @c3.lua 12: local pattern = P(true) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 17: return pattern / text @c3.lua 24: + Pi "CSeq" @c3.lua 12: local pattern = P(true) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 14: pattern = pattern * (P(c:lower()) + P(c:upper())) @c3.lua 13: for c in text:gmatch(".") do @c3.lua 17: return pattern / text @c3.lua 26: local word = (C(ALPHA) * C(ALPHA^0)) @c3.lua 29: end @c3.lua 30: local other = C((P(1) - ALPHA)^1) @c3.lua 31: local hdr = Cs((id + word + other)^1) @c3.lua 35: end @c3.lua 33: function canonical(header) @c3.lua 35: end @c3.lua 38: print(canonical "return-from") @c3.lua 34: return hdr:match(header) @c3.lua 28: return i:upper() .. r:lower() @c3.lua 28: return i:upper() .. r:lower() @c3.lua 39: print(canonical "message-id") @c3.lua 34: return hdr:match(header) @c3.lua 28: return i:upper() .. r:lower() @c3.lua 40: print(canonical "mime-version") @c3.lua 34: return hdr:match(header) @c3.lua 28: return i:upper() .. r:lower() @c3.lua 41: print(canonical "cseq") @c3.lua 34: return hdr:match(header)
I also recorded the execution with LuaJIT (it's faster because it compiles Lua into native code) and it, too, is not sufficiently smart to lift the constant code out of the function. It may be that detecting this is hard for a compiler to do, or that such transformations might not be considered safe (due to possible side effects).
In any case, I found it a bit surprising (although in retrospect, it shouldn't have been).
Saturday, February 14, 2015
I do belieive it's a holiday today
Sunday, February 15, 2015
Notes on an overheard conversation about a bouquet of flowers bought for Saint Valentine's Day
“Did you see what I did to the flowers you gave me?”
“…”
“…”
“…”
“…”
“Oh! You added some flowers to it!”
“I was starting to get worried there for a moment, but you managed to save yourself.”
Monday, February 16, 2015
Timing out Lua coroutines
Time for “that's for another post”—this time, handling timeouts in Lua coroutines.
So, I have this Lua coroutine running, and I want to make a DNS request:
host = dns.request("www.conman.org.","a")
It takes a non-trivial amount of time—time that could be used to run other coroutines. But the operation could take longer than expected (say, two seconds, one second longer than we want to wait) or never even complete (because we lost the request packet, or the reply packet). In that case, we want to timeout the operation.
Step one—let's set a limit to how long we can run:
timeout(1) -- time out in one second host,err = dns.request("www.conman.org.","a") -- DNS query timeout(0) -- no longer need the timeout
The trick now is to implement the code behind timeout()
.
First we need to have some way of storing the coroutines (technically, a
reference to the coroutine) that are waiting to timeout, and some easy way
to determine which ones are timed out. For this, I used a binary
heap, or techically, a “binary min heap” to store the coroutine
reference. The “min” variation because the nodes are ordered by the
“awake” time, and times in the future are larger (and thus, the next
coroutine that will timeout next will always appear in the first spot in the
binary min heap).
Along with the awake value and the coroutine reference, I have a trigger flag. This flag is important for the “cancelling a timeout” case. An earlier version of the code searched sequentially through the list, making “cancelling” an expensive operation (O(n)) compared to “setting” a timeout (O(log(n))). I decided it was easier to just have a flag, and keep a secondary index, keyed by coroutine, to the correct node in the binary min tree. That way, cancelling a timeout is cheap (an amortized O(1)) with the following code:
function timeout(when) local co = coroutine.running() if when == 0 then if TQUEUE[co] then -- guard to make sure we have an entry TQUEUE[co].trigger = false -- disarm timeout trigger end else TQUEUE:insert(when,co) -- otherwise, set the timeout end end
(I should note that the code I
presented last Thursday was buggy—I realized I wasn't keeping the
invariant condition necessary for a binary min heap (child nodes have a
larger value than the parent node) by setting the awake
field
to 0 (a child would then have a smaller value than its parent)—it didn't
break the code but it did make it behave a bit oddly)
I also maintain a run queue—a list of coroutines that are ready to run, used in the main loop:
function mainloop() local timeout = -1 -- the timeout to wait for new packets local now = clock.get() while #TQUEUE > 0 do -- check timeout queue local obj = TQUEUE[1] -- next coroutine to timeout if obj.trigger then -- do we trigger? timeout = obj.awake - now -- if so, when if timeout > 0 then -- if now now (or before) break -- stop looking through the timeout queue end table.insert(RQUEUE,obj) -- insert coroutine into the run queue end TQUEUE:delete() -- delete the entry from the timeout queue end if #RQUEUE > 0 then -- if there's anything in the run queue timeout = 0 -- we set our timeout end -- --------------------------------------------------- -- Receive packets and process---see this post for some details; the actual -- code this isn't -- --------------------------------------------------- for _,event in ipairs(poll:events(timeout)) do event.obj(event) end -- ----------------------------------------------------------- -- run each coroutine in the run queue (some details snipped) -- ----------------------------------------------------------- while #RQUEUE > 0 do local obj = table.remove(RQUEUE,1) if coroutine.status(obj.co) == 'suspended' then coroutine.resume(obj.co) end end return mainloop() end
The code initially sets the timeout to wait for network activity to
-1
, or “wait indefinitely.” It then runs through the timeout
queue, checking each item to see if there's a coroutine that's triggered to
run. If it comes across a coroutine that has been “disarmed” then it's
simply ignored and deleted from the timeout queue. Otherwise, it checks to
see if the awake time is still in the future and if so, it's done with the
timeout queue; otherwise, it moves the coroutine reference to the run queue
and deletes it from the timeout queue.
Eventually, it'll get out of tha loop with a timeout of “indefinite” (if there were no coroutines waiting for a timeout) or some fixed amount of time until the next coroutine times out. It then checks the run queue, and if there is anything in that list, it sets the network activity timeout to 0 (if there is no packets, return immedately).
It then checks for network packets and for each one, process the packet (which in turn might schedule more coroutines to run). After that, it then goes through the run queue, resuming each coroutine in the list. After that, it starts over again.
Tuesday, February 17, 2015
It's a limitation in implementation, not in specification
(I'm responding inline, and I'm not looking at all the aforementioned posts/comments, so forgive me if I'm missing something here.)
It sounds like you're arguing that SRV records are no slower than A records, which, on it's face, seems reasonable. A DNS request is a DNS request, and aside from a response being too big for UDP and having to switch to TCP, you should get nearly-identical performance.
The part, to me, that looks like a real performance issue is potentially having to double the minimum amount of queries to serve a website. We couldn't possibly switch directly to SRV records; there would have to be an overlap of browsers using both SRV and A records for backwards compatibility.
If we stick with that invariant, then we can say that the first-load cost of a page not using SRV records doubles in the worst case: websites that only have an A record. Now we're looking for a SRV record, not getting it, and falling back to an A record. So, now, all of the normal websites who don't give a crap about SRV records, won't ever use them, pay a performance penalty. A marginal one, sure. but it's there.,
So, overall, their claim seems valid, even if low in severity.
I'd love to hear from someone that has the data, but I can count on one hand the number of times where a loss of IP connectivity has happened where I wish I had SRV records for load balancing. It's usually bad DNS records, or slow/bad DNS propagation, or web servers behind my load balancers went down, or a ton of other things. Your point is still totally valid about being able to more easily load balance across multiple providers, datacenters, what have you… but I'm not convinced it's as much of a problem as you make it out to be.
The argument being presented is that DNS SRV resource records should be used more often than they are (I agree), but that to use them for HTTP during a transitional period would lead to a slower web browsing experience as two (or more) DNS lookups would be required— one for the SRV RR, and if that failed, a followup A RR lookup for the IP address (or worse, an AAAA RR lookup for an IPv6 address and then fallback to an A RR lookup). But that's only the case because of a stupid limitation on a particular implementation of DNS that happens to hold, oh, 80% of the DNS traffic on the web (and 97% of all statistics are made up on the spot).
I only noticed this when I wrote my own DNS parsing routines and was testing them out. The specification, RFC- 1035, describes the format for a DNS packet:
Header | |
---|---|
Question | what RRs are we interested in |
Answer | RRs that match our question |
Authority | RRs pointing toward an authority |
Addtional | RRs holding additional information |
And the “Header” section contains four 16 bit fields, described as such:
QDCOUNT an unsigned 16 bit integer specifying the number of entries in the question section. ANCOUNT an unsigned 16 bit integer specifying the number of resource records in the answer section. NSCOUNT an unsigned 16 bit integer specifying the number of name server resource records in the authority records section. ARCOUNT an unsigned 16 bit integer specifying the number of resource records in the additional records section.
RFC-1035: Domain Implementation and Specification"
Take special note of the QDCOUNT
field—“number of entries in
the question section.”
Nowhere in RFC-1035 states that “QDCOUNT
shall be
one, and one shall be the only number in QDCOUNT
, which shall be
one, and nothing more shall appear therein. Amen.” Nowhere.
So, in theory, a program can ask for the following RRs in a single DNS packet: SRV, AAAA and A. But sadly, in theory, there is no difference between theory and practice, but in practice … sigh. You need three separate queries because the most popular DNS server in use decided to support only a single question.
Update at 9:09 PM, Wednesday, February 18th, 2015
It might not take multiple requests, even on that DNS server …
Wednesday, February 18, 2015
Remains of the cake
Sadly for Edvard, someone got to the cake before he did.
A limitation sure, but it sneaks around its own limitations
I was reminded by Yesterday's post on DNS that I was playing around with SRV records, and oh yes, here's a few I set up some time ago:
_http._tcp IN SRV 1 1 8888 lucy IN SRV 2 10 8888 marvin IN SRV 2 20 8888 bunny-desktop IN SRV 2 30 8888 saltmine
So, let's see what I get when I query
_http._tcp.roswell.area51.
(the “home domain” I use around
here):
rcode = 0.000000, ra = true, aa = true, query = false, ad = false, rd = true, cd = false, tc = false, id = 1234.000000, question = { class = "IN", name = "_http._tcp.roswell.area51.", type = "SRV", },
Okay, so far, this is expected—some DNS flags, and the “question” we asked. Continuing …
answers = { [1] = { port = 8888.000000, type = "SRV", name = "_http._tcp.roswell.area51.", weight = 30.000000, target = "saltmine.roswell.area51.", class = "IN", ttl = 86400.000000, priority = 2.000000, }, [2] = { port = 8888.000000, type = "SRV", name = "_http._tcp.roswell.area51.", weight = 1.000000, target = "lucy.roswell.area51.", class = "IN", ttl = 86400.000000, priority = 1.000000, }, [3] = { port = 8888.000000, type = "SRV", name = "_http._tcp.roswell.area51.", weight = 10.000000, target = "marvin.roswell.area51.", class = "IN", ttl = 86400.000000, priority = 2.000000, }, [4] = { port = 8888.000000, type = "SRV", name = "_http._tcp.roswell.area51.", weight = 20.000000, target = "bunny-desktop.roswell.area51.", class = "IN", ttl = 86400.000000, priority = 2.000000, }, },
Okay, these are the answers we were looking for, but wait? What's this?
additional = { [1] = { type = "A", name = "lucy.roswell.area51.", address = "192.168.1.10", class = "IN", ttl = 86400.000000, }, [2] = { type = "AAAA", name = "lucy.roswell.area51.", address = "fc00::1", class = "IN", ttl = 86400.000000, }, [3] = { type = "A", name = "marvin.roswell.area51.", address = "192.168.1.13", class = "IN", ttl = 86400.000000, }, [4] = { type = "AAAA", name = "marvin.roswell.area51.", address = "fc00::3", class = "IN", ttl = 86400.000000, }, [5] = { type = "A", name = "bunny-desktop.roswell.area51.", address = "192.168.1.16", class = "IN", ttl = 86400.000000, }, [6] = { type = "AAAA", name = "bunny-desktop.roswell.area51.", address = "fc00::2", class = "IN", ttl = 86400.000000, }, [7] = { type = "A", name = "saltmine.roswell.area51.", address = "192.168.1.18", class = "IN", ttl = 86400.000000, }, [8] = { type = "AAAA", name = "saltmine.roswell.area51.", address = "fc00::4", class = "IN", ttl = 86400.000000, }, },
Yes, even though I run that braindead DNS implementation that only accepts single questions, it also preemptively sent back the appropriate IP addresses!
Will wonders never cease. There's probably no need for multiple DNS queries to handle SRV lookups.
Thursday, February 19, 2015
“Some people, when confronted with a problem, think ‘I know, I'll use regular expressions.’ Now they have two problems.”
All I can say is that I'm very happy that I'm writing “Project: Sippy-Cup” in Lua. Lua not only makes text manipulation easy, (heck, most scripting languages like Python or Ruby can easily manipulate text) but also that it has the wonderful LPeg that makes writing parsers not only easy, but easier to understand, unlike regular expressions.
And processing SIP messages is pretty much nothing but text parsing and manipulation, with a little bit of networking on the side.
Friday, February 20, 2015
Requiem for a dream
One day while sitting on the couch I noticed that the perspective of the lamp was odd, like inverted. It was still in 3D but… just‥ wrong. (It was a square lamp base, red with gold trim on 4 legs and a white square shade). I was transfixed, I couldn't look away from it. I stayed up all night staring at it, the next morning I didn't go to work, something was just not right about that lamp.
I stopped eating, I left the couch only to use the bathroom at first, soon I stopped that too as I wasn't eating or drinking. I stared at the fucking lamp for 3 days before my wife got really worried, she had someone come and try to talk to me, by this time my cognizance was breaking up and my wife was freaking out. She took the kids to her mother's house just before I had my epiphany…. the lamp is not real…. the house is not real, my wife, my kids… none of that is real… the last 10 years of my life are not fucking real!
Via Jason Kottke, temptotosssoon comments on Have you ever felt a deep personal connection to a person you met in a dream only to wake up feeling terrible because you realize they never existed?
There's a Star Trek: The Next Generation episode, “The Inner Light,” where Picard is knocked unconscience by an alien probe for about half an hour, but Picard spends a subjective thirty years living life on an alient planet. It's considered one of the best Star Trek episodes and won a ton of awards.
The article presented above appears to be a real-life occurrence of subjectively living years of your life in a dream-like state. Only without the alien probes. And the flute.
Saturday, February 21, 2015
Procedures in Experimental Physics
I never epxected that mentioning the book Procedures in Experimental Physics on Hacker News would prove to be so popular.
Wow.
The twilight of quantum mechanics
Quantum mechanics is weird only because we don't learn statistics in high school (well I didn't anyway), and we can't come up with good real- life analogies for quantum interactions.
For example, the twin-slit experiment used to illustrate collapsing the wave function (a single electron fired through 2 slits will show a wave interference pattern on the wall, but the pattern disappears if you find out which slit the electron passed through) is portrayed by physicists as obscure, weird, arcane, or even as indecipherable devil magic which us mere mortals can never strive to intuitively understand beyond pulling out a PDE.
This flat-out isn't true, and here is my analogy for the 2x slit experiment in real life (using trashy fiction):
The electron is an young impressionable female, slit A is the handsome vampire, and slit B is the wild werewolf. Until absolutely forced to pick one of the slits, the electron sort of strings both slits along (and the result is a lot of interference which, in the literary world, we call plot). But, when the reader looks at the end, she (the electron) inevitable picks one of the slits. Summed over all the trashy romance fiction out there, one gets the feeling it's the same damn electron and two slits everywhere, yet she is clearly making different decisions each time.
Quantum mechanics is weird only because we don't learn statistics in high school… | Hacker News
I really have nothing else to add.
Sunday, February 22, 2015
Adult Wednesday Addams
Oooh! Cool! The new season of Adult Wednesday Addams is here!
This web series is based more on the severe, deadpan witted Wednesday Addams of the movie rather than sweet-natured but macabre Wednesday Addams of the TV show, which makes it worth watching (in my opinion).
Monday, February 23, 2015
Looking Glass Falls is looking a bit brittle these days
On the way back from Hike From Hell (an appropriate name, given we hiked to the Devil's Courthouse) we did stop off at Looking Glass Falls:
But that was back in October.
Earlier this week, it wasn't quite so moving, what with the weather in Brevard, NC being quite a bit below freezing.
You know, I never gave it any thought if waterfalls could freeze …
Tuesday, February 24, 2015
Notes from lunch at a Thai restaurant somewhere in Ft. Lauderdale, Florida
As I was sliding my way into the booth, I noticed that the older gentleman in the booth next to ours had an uncanny resemblance to William Gibson, a writer well known for his cyberpunk novels Neuromancer, Count Zero and Mona Lisa Overdrive. It was amazing to think that I might be in the presense of the William Gibson, but I did a quick scan of the restaurant, on the lookout for Neal Stephenson, cyberpunk author as well, known for Snow Crash, The Diamond Age and Cryptonomicon. It was too much to hope for, and too terrible to contemplate the both of them being in the same place.
If you play in someone else's sandbox, don't get upset as they change the rules on you—it's not your sandbox to do as you please
While I realize that I have the knowledge and skills to run my own blog on my own server, I am, nonetheless, grateful that I can, for it appears that Google is now dictating what you can and cannot post publicly on Blogger (link via Flutterby).
Wednesday, February 25, 2015
The unintentional conspiracy
So why am I typing this on a laptop running GNU/Linux, the free software operating system, not an Apple or Windows machine? And why are my phones and tablets running a privacy-enhanced offshoot of Android called Cyanogenmod, not Apple’s iOS or standard Android?
Because, first of all, I can get my work done fine. I can play games. I can surf endlessly. The platform alternatives have reached a stage where they’re capable of handling just about everything I need.
…
Control is moving back to the center, where powerful companies and governments are creating choke points. They are using those choke points to destroy our privacy, limit our freedom of expression, and lock down culture and commerce. Too often, we give them our permission—trading liberty for convenience—but a lot of this is being done without our knowledge, much less permission.
Via Reddit, Why I’m Saying Goodbye to Apple, Google and Microsoft — Backchannel — Medium
While I'm sympathetic to his views, I don't believe there's one vast conspiracy to restrict consumers' use of computers. Each step, taken in isolation, is understandable, but when viewed over time, can appear to be a vast conspiracy.
Take Apple's control over the applications that can run on its devices (the article limits itself to programs that run on the iPhone or iPad, but even on their general computer line, the Mac, Apple is slowly clamping down—on my work-issued Mac laptop I had to dive deep into the settings so I could run programs I wrote myself on the laptop). They do it to enhance the user experience, going back as far as 1984 with the release of the first Macintosh. A major complaint at the time was the inability to modify the computer as there were no expansion slots. But on the flip side—it made the Macintosh easier to use and more stable.
Sure, you could add new hardware to a PC running MS-DOS, but it wasn't particularly easy to do (mainly due to a hardware limitation in the original IBM PC that other manufacturers followed to remain fully compatible wherein users had to learn about device addressing and IRQ settings) and there was always the chance that the device driver (a special program for talking to the hardware) for the device (and most likely not written by Microsoft) could have bugs that crashed the machine (at best—at worse it could silently corrupt memory). By fully controlling the hardware and restricting the upgrades, Apple could ensure a better user experience for The Rest Of Us™.
And now it's more than just hardware. Compter viruses (and yes, that is the proper plural for more than one computer virus) and worms are nothing new (The Shockwave Rider, a science fiction book first published in 1975, was partially about computer worms) but with the commercialization of the Internet in the mid 90s, the threat of malware has grown to such proportions (even images can be a vector for malicious computer code) that it makes sense to severely restrict what can run on a computer and restrict what the program can do (hence my having to tweak settings on my own laptop to allow me to run my own software). And Apple, by restricting the software that is allowed to run on their equipment, can curate the software, again, to make for a better user experience For The Rest Of Us™.
There's also a myth that large companies like Apple and Microsoft are trying to prevent The Rest Of Us™ from programming our own computers. During the rise of the home computer, the 70s and 80s, pretty much every computer sold came with some form of programming environment, even if the langauge was as simple as BASIC. But at the time, that was a selling point, primarily because there wasn't the large market for prewritten software that there is today. With the rise of shrinkware, there was less need to provide a programming environment with each computer.
And frankly, the number of people who buy computers and don't want to program outnumber the people who do want to program. By a lot (I attended high school in the mid 80s and took Pascal. I can probably count on one finger the number of people in that class who are still programming today. People, in general, don't want to program). There was pressure to lower the price of computers (there was a lot of competition in the 80s and 90s) and market research probably revealed that not many people cared about programming, and hey, if the customers don't care about BASIC, that's an easy thing to remove to lower the price. No, there's no vast conspiracy to keep people from programming, just a lack of interest.
I also run my own email server. I personally don't find it all that hard, but then again, I've been managing servers since the mid 90s and by now, I know the ins and outs of running an email server (harder these days than in the early 90s, long before spam and HTML laden emails deluged the Internet) but not many people want to bother with that, and I'm including people who could, in principle, run their own email servers. It's easier to leave that to a company that specializes in running email servers.
In fact, it's easier to rent computers in a data center than to own your own computers in a data center and leave the actual hardware up to companies that specialize in running them (and yes, I'm a person who rents a “computer” at a data center because it is cheaper and I don't have to bother with buying and managing the hardware, so even I am not completely immune to convenience). But I realize there's a risk with not having physical ownership of the hardware and for now, I can live with that risk.
But a vast conspiracy? Nah. I just don't see it.
Thursday, February 26, 2015
I feel the earth, move, under my feet
It's a bit disconcerting when the office is shaking. It would be one thing if I worked in The Los Angeles Office of The Corporation, but I'm don't—I work in The Ft. Lauderdale (as in Florida) Office of The Corporation (and besides, we don't have an office in Los Angeles).
I'm not alone in this—I asked around and yes, other people felt it too. It wasn't a violent “up and down and oh my God we're all going to die!” type of shaking, more of a “I can just make out this vibration in the floor; the building isn't going to collapse on us, is it?” type of vibration.
The only consolation (and it's not much) is that this isn't the first time this has happened.
And no one can explain why …
Update later today
My friend and fellow cow-orker B mentioned on GoogleMyFacePlusSpaceBook that the shaking was caused by frieght trains going by. It makes sense, seeing how there's a railroad right next to the building.
More unintentional conspiracies
Giving most people a “general purpose computer” these days is giving them enough rope to hang themselves. That’s why people that have never learned computers (or did and hate them) like iPads so much. It’s extremely difficult to mess anything up, and you don’t have to worry about antivirus and updating java and flash and all this other crap. Apps are sandboxed, privacy is taken seriously, background apps (spyware) can’t track you, etc.
As someone concerned with security, I’ll gladly tell people to switch from a virus-laden Windows laptop to an iPad or Chromebook.
As someone concerned with privacy, I’m conflicted in offering those suggestions because the security comes from proprietary app stores and review teams, trusting all your data to be stored by the GOOG, not having the ability to run your own code, etc.
Maybe it’s just as simple as: there is not one solution for everyone. Let the majority of people that have no interest in running their own code use iPads and Chromebooks. For developers and people that know enough to take precautions, keep using Macbooks and Thinkpads and whatever.
A story about Jessica | Lobsters
This is a comment on A Story About Jessica, and is presented here just as another data point about giving up control over our own computers.
Friday, February 27, 2015
Saving Private Data
We tell ourselves “once on the internet, always on the internet,” like maintaining content is a trivial thing. But it isn’t a trivial thing — at any time, the company that you rely on to keep your content for free could change their policies, or get bought out and change their policies, or decide they want to go public and change their policies, or simply go under and take your content with them.
The longevity of data requires more intent than this. My advice is to seriously consider migrating to a self-hosted site if you can. If you can’t make sure you export your data with some regularity.
Through some oh-so-very “Not Safe For Work” links (unless, of course, you work in the “adult industry,” in which case, the links are probably sfe) via Flutterby, Google Takes Back Adult Ban | /Slantist
If you consider your data important (and I think you should) and you are using a company to store (or manage) your data, then you must assume it can go away in an instant. No, really, the Internet is littered with dead companies that promised to keep your data “safe.” And you should keep you eye on the ones still alive, for there's no guarentee they'll be around tomorrow.
You might want to peruse The Archive Team while they're still around for more on this topic. Your data will thank you for it.
Saturday, February 28, 2015
A two inch cutting board on a table saw
Now that Bunny's brother has received his gift, I can talk about it. This past Monday on a whim, Bunny made this tiny cutting board:
The thing was, she made this with her table saw! You know, this huge monsterous thing with a 12″ or 14″ circular blade o'death spinning at a bazillion revolutions per second? Yeah, she made this teeny little cutting board with that.
But she made it to test out the capabilities of a new piece of equipment she bought—the Micro Jig GR-100 GRR-Ripper. It's a pretty amazing device used to push wood around and through the many spinning blades o'death that lurk in the wood shop (in our case, the garage). We've seen it used enough times (yes, we watch Steve Ramsey every week) that Bunny felt it might be worth getting.
And yes, it was worth getting. The demonstration videos that come with it are astounding (most impressive to me was cutting dados in a dowel). In fact, she was so impressed that she got a GRRR-Ripperfor her brother, and sent along the cutting board as an example of the type of work possible when using it.
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 …
Wednesday, April 01, 2015
I solemnly swear that on this April Fools' Day I will not post a fake engagement photo on MyFaceGoogleBookPlusSpace like some kind of asshole. Nor will I perpetuate a celebrity death hoax. Because that makes people sad. In fact, I will not play any practical jokes. And if I see someone planning a prank, I will say to them: “Hey, you're being a dick right now. Stop being a dick. Stop being a dick. Seriously, stop being a dick.”
Seriously, take the pledge. The rest of the world will thank you for it.
Serializing Lua data, part III
Continuing the series on Lua serialization, we resume with the Lua userdata type. At this point, all I'm doing is conjecture, since I haven't actually bothered with serializing userdata and this post is about why I didn't bother.
The Lua manual has this to say about userdata:
The type userdata is provided to allow arbitrary C data to be stored in Lua variables. A userdata value represents a block of raw memory. There are two kinds of userdata: full userdata, which is an object with a block of memory managed by Lua, and light userdata, which is simply a C pointer value. Userdata has no predefined operations in Lua, except assignment and identity test. By using metatables, the programmer can define operations for full userdata values (see §2.4). Userdata values cannot be created or modified in Lua, only through the C API. This guarantees the integrity of data owned by the host program.
Already we're in trouble with respect to serialization. The light userdata is just a pointer, no more, no less. There is no indication of just how much memory it points to, much less what it points to or what the memory even represents. That's not to say that a light userdata has no meaning, but such meaning is only applicable to any code written in C (or C++) and not to Lua.
The serialization code gets a light userdata and … meh? There is nothing we can safely serialize about a light userdata. One answer might be to serialize the pointer value, but a pointer value only has meaning within an instance of a program. Run the same program again, and the value of the light userdata might not be the same (nor should you assume it'll be the same). Give that pointer value to another program, and who knows what it points to in that other program.
We could try reading the memory the light userdata points to, but as I said, there is no indication of how much memory we can read, if any. In general, serialization of light userdata is out of the question (I'm not saying it can't be done, I'm just saying I'm not writing a general purpose serializer that will attempt it).
A full userdata, while it still has no meaning for Lua, does have a length associated with it, so it is conceivable we could serialize the actual memory associated with a full userdata but again, we run into trouble. For instance, let's try to serialize the only standard Lua userdata—the result of opening up a file.
The userdata associated with a file in Lua is the following structure:
typedef struct luaL_Stream { FILE *f; lua_CFunction closef; } luaL_Stream;
The first field is a pointer to a FILE
,
an opaque type (even to C programmers) that represents an “open file,”
and sending the actual FILE
value across is meaningless;
one, because the contents differ from system (say, Microsoft Windows) to system (Linux),
and two, it supposes that the “file” being opened exists when this is deserialized and used.
Now, given that CBOR allows additional semantics to be attatched to data, we could include the contents of the “open file” as part of the serialization and semantically tag the data as a “file, please create and open this.” We could, but there are a few issues even with this—what if the “open file” isn't a file at all? What if it's the output from a command? Or a network connection? How you do serialize a connected TCP connection? But say that we do have, in fact, a file, one that happens to be two gigabytes in size? Would you really want to serialize a two gigabyte file?
So solve those issues, there's still the issue of how the file was opened. Was it opened “read only?” We need to send a copy. “Write only?” No need to send anything. But the issue here is—there is no standard way to determine if a file was opened “read-only” or for “write-only” or even “read/write but writes are appended.” There are non-standard ways of doing it, but it varies from system to system.
Now,
about that second field.
It's a pointer to a C function,
and as I stated before,
serializing a Lua function in C is not possible.
I worked around it by tagging the name of the function,
but there's no name for this function,
at least, one known to Lua.
And why point to a hidden function to close the file?
Because for files,
you need to call the C function fclose()
,
but for a “file” opened by popen()
(a function to run another process and either write data to it,
or read data from it)
you need to call the C function pclose()
.
That's why the function pointer.
And that's for a well known, standard Lua userdata. There are other types of userdata, depending upon the Lua modules in use, such as LPeg (where the full userdata for that represents an entirely different virtual machine geared for parsing text) or even my own org.conman.pollset (which is usually used to multiplex I/O with network connections, but can be used for other devices such as serial ports, and whose implementation depends on the operating system, as if things weren't difficult enough).
This also depends upon the module handing a given full userdata already loaded when deserializing. I'm not saying this is all impossible, but I do think it's beyond the scope of a general library to handle. Perhaps having the user register some type of callback to handle userdata might be required. I already support callbacks for tagged CBOR data, so adding support for full userdata using callbacks shouldn't be that hard.
All that's left—threads.
Thursday, April 02, 2015
Thank god that's over with!
At least yesterday is now over and those suffering from aphrilophobia can climb out from under their beds and go about their business for the next 365 days (next year being a leap year).
Serializing Lua data, part IV
The last Lua data type to serialize—threads.
It's more difficult than serializing a function, but probably a bit easier than serializing a userdata. Possibly. I haven't actually tried it yet, as it can't be done through Lua.
The issue is that there's no API to manipulate the callstack, and without that, you're stuck with dipping into the internals of Lua via C, which explains why most existing serialization modules haven't bothered with threads. And the only one that has attempted it, only works for Lua 5.1.
And that's why I didn't bother with it, either.
It was an interesting experience to write a serialization library for Lua. It became apparent exactly why so many don't bother with functions, userdata or threads—they're not easy to universally support.
I also skipped out on supporting metatables, not because they're hard, but because I just didn't get around to it. I also think that CBOR makes for a good serialization format. The primitives are well chosen, it's a consistent format and the semantic tagging makes it easy to extend.
And like I said earlier, I had fun playing around with this stuff.
Friday, April 03, 2015
A little snippet of permutations
I'm working on a little Lua project, and I found myself with a surprisingly hard problem. The task, take the following string:
one/{two three four five}/alpha/beta/{gamma delta epsilon}.c
and generate all possible permutations of the string with the words in the braces appearing once. In essence, generate the following list:
one/two/alpha/beta/gamma.c one/two/alpha/beta/delta.c one/two/alpha/beta/epsilon.c one/three/alpha/beta/gamma.c one/three/alpha/beta/delta.c one/three/alpha/beta/epsilon.c one/four/alpha/beta/gamma.c one/four/alpha/beta/delta.c one/four/alpha/beta/epsilon.c one/five/alpha/beta/gamma.c one/five/alpha/beta/delta.c one/five/alpha/beta/epsilon.c
Parsing the string into a usable format was trivial (code left to the reader—hint: LPeg). So, starting from the output of parsing:
{ "one/", { "two", "three", "four", "five" }, "/alpha/beta/", { "gamma", "delta", "epsilon", }, ".c" }
Then … what?
You have to iterate through the main table, and at the same time, iterate through any subtables that might exist (anywhere from zero on up). It took me a while to come up with the code. I knew that there was an elegant way to do this, and by God, I was going to find it.
Several hours later, and:
-- *************************************************************** -- -- Copyright 2015 by Sean Conner. All Rights Reserved. -- -- This library is free software; you can redistribute it and/or modify it -- under the terms of the GNU Lesser General Public License as published by -- the Free Software Foundation; either version 3 of the License, or (at your -- option) any later version. -- -- This library is distributed in the hope that it will be useful, but -- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- License for more details. -- -- You should have received a copy of the GNU Lesser General Public License -- along with this library; if not, see <http://www.gnu.org/licenses/>. -- -- Comments, questions and criticisms can be sent to: sean@conman.org -- -- ******************************************************************** -- *********************************************************************** -- Lua 5.3 renamed the unpack() function to table.unpack(). So check for -- Lua 5.3 and handle accordingly. -- *********************************************************************** if _VERSION == "Lua 5.3" then unpack = table.unpack end -- *********************************************************************** -- This will take an array of strings and tables, and return an iterator -- that will return successive permutations of strings. -- -- The table is unpacked into arguments, and the add() function will slowly -- walk down the argument list, calling itself recursively to generate all -- possible strings from the list of arguments and yield them one at a time. -- -- The expand() function will create the coroutine and return a function -- usable by the for keyword. -- *********************************************************************** function expand(list) local function add(a,x,...) -- ------------------------------------------------------------ -- if x is nil, then we've exhausted all the paramters and have -- accumulated a string we can yield. So yield it up. -- ------------------------------------------------------------ if not x then coroutine.yield(a) -- -------------------------------------------------------------- -- if x is a string, call ourselves with the contatenation of our -- accumulator string with x, and the rest of the paramters -- -------------------------------------------------------------- elseif type(x) == 'string' then add(a .. x , ...) -- ---------------------------------------------------------------------- -- otherwise, we have a table. So iterate through the table, calling -- ourselves each time with an updated accumulator value and the rest of -- the parameters. -- ---------------------------------------------------------------------- elseif type(x) == 'table' then for i = 1 , #x do add(a .. x[i], ...) end end end return function(co) local okay,res = coroutine.resume(co) return res end,coroutine.create(function() add("",unpack(list)) end) end -- *********************************************************************** -- The parsing of -- -- one/{two three four five}/alpha/beta/{gamma delta epsilon}.c -- -- into a table is left to the reader for an exercise. For right now, I'm -- using a hardcoded table. -- *********************************************************************** test = { "one/", { "two", "three", "four", "five" }, "/alpha/beta/", { "gamma", "delta", "epsilon", }, ".c" } -- *********************************************************************** -- And now, just expand the list, printing each result. -- *********************************************************************** for path in expand(test) do print(path) end
It's a decent example of recursion (where the trick is find the right base case and the reductions that lead to said base case). There might be non-recursive solutions, but I shudder at the potential complexity of such solutions.
Saturday, April 04, 2015
Some thoughts on make
From time to time,
I find make
limiting,
think there has to be a better way and I start playing around with the idea of building a new make
.
It's not that uncommon for programmers to think this (SCons,
CMake,
ant,
rake and a bunch of other programs)
but oddly enough,
as I try them,
I keep going back to make
(specifically,
GNU make
;
note that when I mention make
,
I am talking about GNU make).
I think the main reason I go back is that make
is mainly a syntax-light declarative langauge with bits of shell scripting thrown in.
The other build systems are generally based around another language I do not know,
they tend towards being very imperative,
and rarely can you parallelize building the software
(and when you get the makefile right, a parallel run of make
just flies).
So when I had that “let's remake make
” itch this time,
I thought that perhaps I would see if I could stay within the confines of the existing syntax of make
as much as possible.
I wasn't trying to actually program my own make
,
but rather,
just play around with how I would like make
to look and work.
The main problem with make
is declaring the dependencies.
For instance,
I'm embedding a UUID library into a larger project,
and because recursive make is considered harmful,
I include in my makefile:
lib/libspcuuid.a : build/third_party/uuid/luauuid.o \ build/third_party/uuid/uuid_ns_dns.o \ build/third_party/uuid/uuid_ns_null.o \ build/third_party/uuid/uuid_ns_oid.o \ build/third_party/uuid/uuid_ns_url.o \ build/third_party/uuid/uuid_ns_x500.o \ build/third_party/uuid/uuidlib_cmp.o \ build/third_party/uuid/uuidlib_parse.o \ build/third_party/uuid/uuidlib_toa.o \ build/third_party/uuid/uuidlib_v1.o \ build/third_party/uuid/uuidlib_v2.o \ build/third_party/uuid/uuidlib_v3.o \ build/third_party/uuid/uuidlib_v4.o \ build/third_party/uuid/uuidlib_v5.o build/third_party/uuid/luauuid.o : third_party/uuid/src/luauuid.c build/third_party/uuid/uuid_ns_dns.o : third_party/uuid/src/uuid_ns_dns.c build/third_party/uuid/uuid_ns_null.o : third_party/uuid/src/uuid_ns_null.c build/third_party/uuid/uuid_ns_oid.o : third_party/uuid/src/uuid_ns_oid.c build/third_party/uuid/uuid_ns_url.o : third_party/uuid/src/uuid_ns_url.c build/third_party/uuid/uuid_ns_x500.o : third_party/uuid/src/uuid_ns_x500.c build/third_party/uuid/uuidlib_cmp.o : third_party/uuid/src/uuidlib_cmp.c build/third_party/uuid/uuidlib_parse.o : third_party/uuid/src/uuidlib_parse.c build/third_party/uuid/uuidlib_toa.o : third_party/uuid/src/uuidlib_toa.c build/third_party/uuid/uuidlib_v1.o : third_party/uuid/src/uuidlib_v1.c build/third_party/uuid/uuidlib_v2.o : third_party/uuid/src/uuidlib_v2.c build/third_party/uuid/uuidlib_v3.o : third_party/uuid/src/uuidlib_v3.c build/third_party/uuid/uuidlib_v4.o : third_party/uuid/src/uuidlib_v4.c build/third_party/uuid/uuidlib_v5.o : third_party/uuid/src/uuidlib_v5.c
Or, if I wanted to save myself some typing:
define OBJECT_template = $(1) : $(2) endef UUIDSRC = $(wildcard third_party/uuid/src/*.c) lib/libspcuuid.a : $(subst third_party/uuid/src,build/third_party/uuid,$(UUICSRC)) $(foreach target,$(UUIDSRC),$(eval $(call OBJECT_template(build/third_party/uuid/$(notdir $(target)),$(target)))))
and have no idea what is going on three months from now (if indeed, I got that right). Instead, I would like to type:
lib/libspcuuid.a : build/third_party/uuid/*.o build/third_party/uuid/*.o : third_party/uuid/src/*.c
and be done.
This should be possible.
“lib/libspcuuid.a” doesn't exist,
but it depends upon all the “.o” files in “build/third_party/uuid”,
which don't exist,
but we have a rule that says “for ‘.o” files in ‘build/third_party/uuid’,
there should be a corresponding ‘.c” file in ‘third_party/uuid/src/’ that is is generated from.”
Which also leads to another problem with make
:
if “build/third_party/uuid” doesn't exist,
make
should make it!
Automatically!
I mean,
make
has no problems with “uuidlib_v5.o” not existing—that's the reason we're using make
in the first place,
to make files!
If a directory a file lives in doesn't exist,
make
should make that too.
Right?
By the same token, if I wanted to include some Lua modules but not all of them, I would like to do:
SPCMODC = env errno fsys hash math net pollset process strcore sys syslog SPCMODL = debug getopt string table unix lib/libspcmod.a : build/third_party/lua-conmanorg/*.o build/third_party/lua-conmanorg/*.o : third_party/lua-conmanorg/src/{ $(SPCMODC) }.c \ third_party/lua-conmanorg/lua/{ $(SPCMODL) }.lua
(Ah! So that's where yesterday's code snippet came from!)
I'll spare you the expansion.
Another small bit of annoyance is writing implicit rules to build the files.
I learned the hard way that in make
,
this:
%.o : %.c $(CC) $(CFLAGS) -c -o $@ $<
only works if the “.c” and “.o” files are in the same directory! So the above rules works fine for:
long/path/to/src/foo.o : long/path/to/src/foo.c src/bar.o : src/bar.c snafu.o : snafu.c
But not for:
build/foo.o : long/path/to/src/foo.c build/bar.o : src/bar.c build/snafnu.o : snafu.c
Nope, I also have to write:
build/%.o : long/path/to/src/*.c $(CC) $(CFLAGS) -c -o $@ $< build/%.o : src/%.c $(CC) $(CFLAGS) -c -o $@ $< build/%.o : %.c $(CC) $(CFLAGS) -c -o $@ $<
if I want to segregate the “.o” files from the “.c” files.
How hard is it to realize that if I have a “.c” file, then the command to make a “.o” file is the same, regardless of where the “.c” file comes from, or where the “.o” file is being generated. Hello?
And while we're on that subject, one implicit rule I use is the following:
%.o : %.lua $(LUAC) -o $(@D)/$(*F).out $< $(BIN2C) -9 -o $(@D)/$(*F).c -t $(*F) $(@D)/$(*F).out $(CC) $(CFLAGS) -c -o $@ $(@D)/$(*F).c $(RM) $(@D)/$(*F).out $(@D)/$(*F).c
That bit of jibberish first compiles the Lua code using luac
,
then that output is converted to a C file which is then compiled into a object file so I can link it into the final executable,
them removes the temporary files it needed to do all that.
The noise you see is the cruft necessary to specify temporary files that won't get overwritten when doing a parallel build.
Much nicer would be something like:
%.o : %.lua $(LUAC) -o $$.1 $< $(BIN2C) -9 -o $$.2 -t $(*F) $$.1 $(CC) $(CFLAGS) -c -o $@ $$.2 $(RM) $$.1 $$.2
(even better—make
automatically deletes the intermediate files unless I tell it not to)
One complaint about make
(or rather,
makefiles themselves)
is that a change to the makefile does not cause a recompile,
mainly because the makefile itself is never listed as a dependency anywhere.
This is never what you want!
If the makefile was listed as a depenency
(either explicitly or implicitly),
then adding a new file to be compiled in would cause everything to be recompiled,
when it should be the new file,
any files that call code in the new file,
and a final relinking of the code is all that is needed.
Also,
if you change a variable,
like $(LDFLAGS)
,
then all that should happen is any rule that uses $(LDFLAGS)
should be run,
not a complete build.
In other words,
you really have a dependency on a portion of the makefile,
not the makefile as a whole.
But solving this would require a possible rethink of how make
works
(perhaps a cached version of the makefile that mode
checks against,
and intelligently applies the changes as dependencies? You know,
so if you change $(CC)
,
any rule using $(CC)
is automatically run).
I realize these some of my ideas are not that easy to implement
(heck,
I wasted a few hours yesterday writing code to properly build a list of targets and dependencies based on ideas presented here),
but I think they may go a long way to making make
less horrendous to use.
Sunday, April 05, 2015
No Reservations in Narnia this fine Ēostre day
Ah, today's holiday. A celebration of the reanimation of a Jewish carpenter using Nordic symbols, named after a Germanic deity and involving sweets derived from Central American food. Ain't modern life wonderful?
As for me, I'm spending the day reading about Anthony Bourdain's eating his way through Narnia.
Monday, April 06, 2015
Someone bought Casa New Jersey and you have to see what happens next
When I left Casa New Jersey, it needed quite a bit of loving care. But sure enough, someone came along and lavished quite a bit of loving care on the house. And seriously, what a transformation! (link via Spring on GoogleMyFacePlusSpaceBook).
I especially like the work done upstairs. Wow!
Tuesday, April 07, 2015
Just use /dev/urandom and be done with it
I noticed one of the developers at The Ft. Lauderdale Office of The Corporation using the time of day to seed a random number generator,
which is borderline okay
(depending on how the resulting random numbers will be used)
there are better ways to generate a random seed,
at least on a modern POSIX system—read data from /dev/urandom
.
My fellow cow-orker B,
with whom I was having this discussion,
mentioned this borderline paranoid approach to reading /dev/urandom
.
But I think that if you have to call fstat()
to make sure the file is actually /dev/urandom
then you have more things to worry about
(really—if a cracker can substitute /dev/urandom
with known data,
it's pretty much game over—B agreed with that statement,
by the way).
Besides,
the author wasn't paranoid enough! Who's to say there isn't some extra code in there
(say,
via $LD_PRELOAD
or ptrace()
or maybe even through some ELF magic on the executable)
that intercepts the read()
function to return “random data” when reading from /dev/urandom
?
Hmmmm?
(about the only thing you can do to counter that is nuke the site from orbit—it's the only way to be sure)
But in the mean time,
just use /dev/urandom
.
Wednesday, April 08, 2015
Privacy? At GoogleMyFacePlusSpaceBook? Surely you jest!
I was inspecting Facebook's network traffic today in Firefox Devtools, when I realized that any text I put into the status update box was sent to Facebook's servers, even if I did not click the post button. Ever curious, I Googled this behaviour and came across a study which reveals some very frightening information:
Facebook calls these unposted thoughts "self-censorship," and insights into how it collects these nonposts can be found in a recent paper written by two Facebookers.
Via Lobsters, Facebook sending 'nonposts' to its servers and storing unpublished thoughts
I wouldn't be surprised if all the sites in the MyFaceGoogleBookPlusSpaceosphere aren't doing the same thing. And the thing is, when I do a search on “experimenting on unwilling subjects” the results all seem to be Na zis Nazis Nazis for some reason. Just approach FaceGoogleMyPlusSpaceBook that everything posted, whether “private” or not, is going to be seen by everybody. Because it is.
Thursday, April 09, 2015
Harry Potter and the Methods of Rationality
Finally!
Harry Potter and the Methods of Rationality is finally finished! I'm so happy!
I started reading this a few years ago, but the rate of new chapters was never that fast and it's only been in the past month or so that Eliezer Yudkowsky finished writing it. I think the premise is wonderful—that Harry Potter was raised by scientists and skeptically approached magic at Hogwarts by applying rational thought and scientific experimentation. It takes a while to start, but once it does, I found I could not stop reading it (well, until I reached the current chapter and had to wait a several months for the next outburst of chapters).
Over the past two nights, I've finished reading it (staying up way past my bedtime), and I must say, I found He-Who-Shall-Not-Be-Named to be a quite facinating character (when he finally did show up—oh, is that a spoiler?).
I think it's worth the read, all 122 chapters of it. Don't worry, it's a complete story with Harry winning and He-Who-Shall-Not-Be-Named losing and not a seven book series, so don't let the length discourage you if you are a Harry Potter fan—at least now you can finish it in one reading binge if you so desire.
Friday, April 10, 2015
Notes about a conversation overhead in the kitchen at Chez Boca
“Aaaaaaaaaah!”
“What happened?”
“The 16 ounce bottle of vanilla extract fell on the floor!”
“Did the bottle break?”
“No, but there's vanillia extract all over the pantry.”
“Was it the used bottle?”
“It's used now.”
“Is there any left?”
“About a quarter of the bottle is left.”
“Sigh. That was the good stuff.”
“At the very least, it will smell incredible in here for a while.”
Saturday, April 11, 2015
Coyote's Flying Saucer Retrievals and Repairs
It's nice to know that Coyote's Flying Saucer Retrievals and Repairs exists so when my C-57D needs repair, I know where to go to have it checked out. The only bad thing is that it is in California and not in Roswell or Rachel where all the flying saucer activities seem to happen in this country. I guess I'll have to keep in mind that if I crash my C-57D, I need to crash in or near Ocotillo, California.
Sunday, April 12, 2015
For me, SPF is not that great an anti-spam measure
I was reminded of SPF the other day. It's an anti-spam measure, primarily to help identify email spoofing. I set up an SPF record on my domain years ago, but other than that, I haven't really done anything else with it. But being reminded of it, I thought it might be a good idea to see just how effective it could be. I'm already using a greylist daemon to cut down on spam but hey, the more spam that is caught, the better.
First step—just how effective is the greylist daemon? I have the logs from the greylist daemon for the past month (March 15th to April 11th). Some processing on the logs and I have my answer:
Emails accepted | 5,028 |
---|---|
Emails rejected | 5,132 |
Total | 10,160 |
Wow!
A bit over 50% of the emails received by my email server are spam. I'm not sure if I should be depressed that easily half the email addressed to me is spam, or happy that the greylist daemon is an easy way to avoid false positives. I suppose both are in order.
Now, I still get spam despite the greylist daemon, but all that means is that the sender is actually bothering to follow the SMTP protocol—not that high a bar. So, of the emails that do get through, how much would get flagged with SPF? Okay, time to check up on the SPF specification, and boy, is that a mess. The grammar to parse SPF records requires backtracking (lovely!—and lest you think a message from 2010 has any relevence to a 2014 standard, think again; the grammar didn't change all that much) and not entirely context free either (sigh—one letter in the macro-expansion has two meanings depending on where it appears).
Oh, and that grammar? It's actually covers three different grammars—one for parsing the SPF record itself, a second one to parse an email header, and the third a secondary text string via a secondary DNS query (the SPF record itself is obtained via a DNS query, by the way).
Okay, so munging the grammar to what I think is intended and leaving out what I don't need, I went through the log file and for each accepted email, did an SPF check according to the specification. Granted, the data I get now might not reflect the results made at the original time, but it should give me a baseline to go by.
For the test, I pulled out all emails accepted (5,028) and removed those I explicitly allowed (for example, accept anything from a given IP address, or from a given domain) or that did not have a sender address (allowed by the SMTP protocol to prevent mailing loops when generating mail bounce messages), leaving me with 4,343 emails. Then, for those, I looked up the SPF record for the given domain, and if it had one, applied its policy.
The 4,343 accepted emails came from 1,000 unique domains, of which only 433 had an SPF record. Okay, 43% of the domains have an SPF record. And of the domains that had an SPF record, only 629 emails accepted were checked. Or 12½% of all accepted incoming emails could be checked via SPF. Sigh.
But of those that were checked via SPF, how did we fare? Were a lot spam? Or were most acceptable forms of email pef SPF policy?
fail | 43 | IP address was not allowed to send this email |
softfail | 53 | IP address should not be sending this email (used for testing) |
neutral | 90 | IP address has no policy |
pass | 443 | IP address is allowed to send this email |
A 70% pass rate for SPF. Only 43, or almost 1% (or around two per day) could have been deleted as spam. Another 53 maybe, possibly, could have been deleted as spam. And 90 no idea one way or the other. Sigh.
You want to know what has a better rate of catching spam than SPF for my email? Any email addressed to my domain registration email not from the registrar. For me, I don't think it worth the effort to implement this.
Monday, April 13, 2015
One of the most impressive demoscene videos I've ever seen
This is simply amazing.
I'm impressed. I didn't think it was possible to get more than 16 colors from the CGA card and here is a demo showing over 1000 colors. On a stock IBM 5150 PC from 1981 (video via 8088 MPH: We Break All Your Emulators « Oldskooler Ramblings, from a discussion at Hacker News). And for those of you who are curious as to how this was done, there're indepth articles about the graphics programming (via Hacker News) and the sound programming (again, via Hacker News).
Tuesday, April 14, 2015
Honey on tap
The most successful fully funded crowdfunding campaign on Indiegogo is not for a new smartwatch, video game, or 3D printer. It is for a new way to harvest honey, a potential breakthrough in a practice that has not seen a significant technological advance since 1852, when the Rev. Lorenzo Langstroth patented America's first movable frame beehive.
The Flow hive has amassed $8.9 million from more than 25,000 backers in one month (the goal was just $70,000), a possible sign that the urban-hipster revival of beekeeping is still alive, even as the U.S. honeybee population continues to die off. (The USDA has sounded the alarm, estimating that a third of all honeybees have died since 2006. The main suspect is a class of neuro-active insecticides called Neonicotinoids.)
Via Instapundit, This 'Honey on Tap' Beehive Design Just Raised $9 Million on Indiegogo
I've heard of this, but this is the first time I've seen how the Flow™ Hive works, and it's pretty ingenious. I know T, my fellow cow-orker, might be interested in this as he keeps bees as a hobby.
Wednesday, April 15, 2015
The taxman cometh!
Telonephobics beware! For it is the Ides of April and the second
inevitability of life is upon us. But fear not if you lack health
insurance and cannot afford $95 or 1% of your income (whatever is higher)
since it is very easy to avoid paying the penalty tax:
#4. Get beaten by your wife. Required documentation: None
Official text reads: "You recently experienced domestic violence. Required documentation: None."
Translation: Get attacked by your wife. You may then apply for the exemption by simply stating “I am exempt because my wife beat me.” No documentation required.
Via Captain Capitalism, Citizen Liberty: 17 Ways To Avoid The Obamacare Tax Penalty, Including Being Beaten By Your Wife
It doesn't surprise me that a 2,700 page bill that no Congresscritter read and over 33,000 pages of regulations (wow! Something longer than Atlas Shrugged) would have egregious loopholes in it.
Really?
NO DOCUMENTATION?
Sheesh.
Thursday, April 16, 2015
How do I know you're allowed to send me this?
I was pulled into an improptu design meeting at work. Originally it was to discuss the format of a new URI for our Android application to use, but it quickly shifted into an authentication issue on the Android platform.
I don't work on Android applications (I do the call-processing on the telephony network side, not the cellphone side), so my terminology might be a bit off but the gist of the issue is our application, named Awesome Application (name changed to protect me), comes preinstalled on Android phones. We've allowed another preinstalled application, Bodacious Bronies (name completely made up), not written by us, to, when a certain action is done by the user in Bodacious Bronies, launches our application. This is done by Awesome Application listening for an intent sent by Bodacious Bronies, and then doing it's thing.
But the issue the our developer, D, had with this is to prevent the Malevolent Malcontent application (for example) from spamming Awesome Application with repeated intents. The fear here is that Malevolent Malcontent could so annoy the user with our program always popping up that the user would then uninstall Awesome Application, or worse, bitch, complain and moan to the phone carrier to remove or disable our application post-haste.
Our application could check the uid
or the package name of the intent sender and only do the thing it does if the sending application is allowed,
but neither the uid
or the package name is fixed;
either one can change with an update,
and if our application isn't updated with the new uid
or package name,
then our app does nothing since it doesn't know the intent is from an allowed application.
And other methods, like having Bodacious Bronies sign the intent (somehow) is still subject to attacks; in order to sign the intent, a private key needs to be stored with Bodacious Bronies, (and we were sure that the creators of Bodacious Bronies would not want to include a private key with the application) and what's to stop the creators of Malevolent Malcontent from nabbing that private key (the developer of Malevolent Malcontent could get an Android phone, jailbreak it, and extract the Bodacious Bronies private key) and forge intents?
Security is hard. So is authentication.
There is a way to keep intents from being broadcast to every application. D was trying to find a way to avoid this, as one of our customers wanted the broadcast method of intents (for some reason—again, I'm not an Android developer so I'm not sure what the trade-offs are here) but he decided that the best course of action is to use the non-broadcast intent method. Now he has to convince the Powers-That-Be that this is the only way.
Friday, April 17, 2015
Minnesota's great umlaut war is over
Today, we bring you urgent and breaking news out of Minnesota, where a battle over umlauts has been — well, not raging. What is the more polite version of raging? Occurring? Happening? Gently taking place? Something like that.
Anyway! Minnesota. Umlauts. See, there is a city in Minnesota that had been known as Lindström — or, if you saw the signs greeting you on the way in or out of town in recent years, Lindstrom.
Via Brian Yoder on MyFaceGoogleBookPlusSpace, Minnesota’s great umlaut war is over (also, Minnesota was having an umlaut war) - The Washington Post
My first thought was couldn't the MDOT just spell it “Lindstroem?” But then I read that Lindström has a sister city in Sweden, Tingsryd, and I wasn't sure if the umlaut served the same function in Swedish as it did in German. It turns out it doesn't, and the “ö” in Swedish is a distinct character, unlike in German where the “ö” is a shorthand notation for “oe.”
It all turned out fine though, the MDOT is going around adding umlauts on all the Lindström signs.
Ms. L'Engle also never mentioned the 24-hour news cycle that helped subjugate the population of Camazotz
Via a link on FaceGoogleMyBookPlusSpace is an article about a cut passage from an early draft of A Wrinkle In Time. The article talks briefly about the cut passage and then goes into some details about Madeleine L’Engle, but I can't help but quote from the cut passage:
So she said, “But Father, what's wrong with security? Everybody likes to be all cosy and safe.”
“Yes,” Mr. Murry said, grimly. “Security is a most seductive thing.”
“Well—but I want to be secure, Father. I hate feeling insecure.”
“But
not enoughyou don't love security enough so that you guide your life by it, Meg. You weren't thinking of security when you came to resuce me with Mrs Who, Mrs Whatsit, and Mrs Which.”“But that didn't have anything to do with me,” Meg protested. “I wasn't being brave or anything. They just took me.”
Calvin, walking beside them with his load of wood, said, smiling warmly at Meg, “Yes, but when we got here you didn't go around whining or asking to go home where you could be all safe and cosy. You kept yelling, where's Father, take me to Father: You never gave a thought to security.”
“Oh,” Meg said. “Oh.” She brooded for another moment. “But I still don't see why security isn't a good thing. Why, Father?”
“I've come to the conclusion,” Mr. Murry said slowly, “that it's the greatest evil there is. Suppose your great great grandmother, and all those like her, had worried about security? They'd never have gone across the
countryland in flimsy covered wagons. Our country has been greatest when it has been most insecure. Thislonginsick longing for security is a dangerous thing, Meg, as insidious as the strontium 90 from our nuclear explosions that worried you so about Charles Wallace when you read in science at school that it was being found in greater and greater quantities in milk. You can't see strontium 90. You can't feel it or touch it. But it's there. So is the panicky searching for conformity, for security. Maybe it's because of the Black Thing, Meg. Maybe this lust for security is like a disease germ that it has let loose on our land. I don't know, Meg. All I realize now is that my fight is much bigger than this little one on Camazotz.”
Despite being written over fifty years ago, it seems to apply more to us today than it did in 1962 (and here's a discription of Camazotz if you are unfamiliar with the book).
Saturday, April 18, 2015
Sadly, yet accurately, still no flying cars
Tell me, does any of this sound familiar?
(1) Random acts of violence by crazy individuals, often taking place at schools …
(2) The other major source of instability and violence comes from terrorists, who are now a major threat to U.S. interests, and even manage to attack buildings within the United States.
(3) Prices have increased sixfold between 1960 and 2010 because of inflation. …
(4) The most powerful U.S. rival is no longer the Soviet Union, but China. However, much of the competition between the U.S. and Asia is played out in economics, trade, and technology instead of overt warfare.
(5) Europeans have formed a union of nations to improve their economic prospects and influence on world affairs. In international issues, Britain tends to side with the U.S., but other countries in Europe are often critical of U.S. initiatives.
(6) Africa still trails far behind the rest of the world in economic development, and Israel remains the epicenter of tensions in the Middle East.
(7) Although some people still get married, many in the younger generation now prefer short-term hookups without long-term commitment.
(8) Gay and bisexual lifestyles have gone mainstream, and pharmaceuticals to improve sexual performance are widely used (and even advertised in the media).
(9) Many decades of affirmative action have brought blacks into positions of power, but racial tensions still simmer throughout society.
(10) Motor vehicles increasingly run on electric fuel cells. …
(11) Yet Detroit has not prospered, and is almost a ghost town because of all the shuttered factories. However. a new kind of music … has sprung up in the city.
(12) TV news channels have now gone global via satellite.
(13) TiVo-type systems allow people to view TV programs according to their own schedule.
(14) Inflight entertainment systems on planes now include video programs and news accessible on individual screens at each seat.
(15) People rely on avatars to represent themselves on video screens …
(16) Computer documents are generated with laser printers.
(17) A social and political backlash has marginalized tobacco, but marijuana has been decriminalized.
Oh, and let's not forget President Obomi.
Wait—what?
What you read was eighteen predictions (link via Hacker News) made by John Brunner is his 1969 novel Stand on Zanzibar. It's an incredible list, scarily accurate in its portrayal of life in 2010. I never read that book, but I did read Shockwave Rider that predicted a global network besieged with malware and The Sheep Look Up, a book about global environmental collapse that was the single most scary book I've ever read (that I try not to think about too much least I start having nightmares again). Both of those were very good (even if The Sheep Look Up is too horrifying to think about), so I would think Stand on Zanzibar would be great as well.
Sunday, April 19, 2015
The man behind the bits
This self-portrait:
also happens to be a valid QR code. Go head, try it if you can. See how deep the rabbit hole goes.
For the curious, I used QArt Coder to generate the image. And for the really curious, the theory behind how it works.
Monday, April 20, 2015
Just because it was that type of day
Because a picture of a bunny with a pancake on its head is cliché.
Tuesday, April 21, 2015
Notes on an overheard conversation in The Ft. Lauderdale Office of The Corporation
“Do you know how I get to the timesheet application?”
“Timesheet application? You want to apply for some vacation time?”
“Yes.”
“Okay, first you need to log into the VPN.”
“But we're in the office, why do I need to log into the VPN?”
“No, you're thinkging of The Corpration VPN. You need to log into the Corporation Overlord Corporation VPN.”
“Oh. Where do I go to log into that?”
“Here, let me email you the location.”
“Thank you. Hmm … Ah, I use that account name … but I don't seem to know the password for that account. Is it the same as any other password you use?”
“No, it's a different password.”
“Sigh. … Okay it's not that password … and it's not that password. I'm afraid of trying it a third time lest I get locked out.”
“So once you reset your password and can log on, do not select the ‘Timesheet Application’ but instead select the ‘Monopolistic Database Corporation Application Suite’ instead.”
“Do tell.”
“Yeah, I can't make this stuff up even if I wanted to.”
“So skip ‘Timesheet Application’ and instead use the ‘Monopolistic Database Corporation Application Suite.’”
“Yes.”
“I won't ask.”
“Good, beacuse I don't know the answer.”
Notes on another overheard phonecall in The Ft. Lauderdale Office of The Corporation
“Okay, I copied down the new password.”
…
“Wait? I'm stuck with that password?”
…
“Oh, I can't change the password for ten days. Then I can change it to something less obvious.”
…
“Okay, fine. Now let me try logging into the site.”
…
“No, I don't have Internet Explorer.”
…
“No, I'm not running Windows 7, or any version of Windows for that matter.”
…
“A Macintosh.”
…
“No, really.”
…
“No, I'm not running Google Chrome.”
…
“Firefox.”
…
“Is there a joke I didn't get?”
Wednesday, April 22, 2015
Surely you can't be serious
A couple of months ago, I was at a party somewhere, and a boy came up to me who was, like, 8 or 10 years old, and he said, “Oh, I really liked Airplane! I thought it was really funny!” And I said, “How was it that you came to see it?” And he said, “Well, my grandfather made me watch it.” [Laughs.] If you’d told us in 1980 that the grandkids of the audience would be the ones who’d keep the movie going, it would’ve been very gratifying. But I don’t think we ever anticipated it. And it’s one of the great thrills, I think, of all of our lives that it still remains well known.
Via Instapundit, Surely you can’t be serious: An oral history of Airplane! · Oral History · The A.V. Club
It's an oral history of the making of “Airplane!” from many people who were involved in the making of one of the funniest movies to ever come out of Hollywood. And stop calling me Shirley.
Thursday, April 23, 2015
Gotta love spam with a legal disclaimer
- From
- "John" <yjonjens@mail.com>
- To
- sean@conman.org
- Subject
- business leads
- Date
- Thu, 23 Apr 2015 17:22:50 +0200
Hey,
You are receiving this email because we wish you to use our email marketing service.
We wish to be your email marketing partner, we can grow your business 2-5 times than now.
If you would require more information please send us an email and we would be glad to discuss the project requirements with you soon. Looking forward to your positive response.
Kind Regards
John
Email: pottleyo@aliyun.com
This e-mail message and its attachments (if any) are intended solely for the use of the addressee(s) hereof. In addition, this message and the attachments (if any) may contain information that is confidential, privileged and exempt from disclosure under applicable law. If you are not the intended recipient of this message, you are prohibited from reading, disclosing, reproducing, distributing, disseminating or otherwise using this transmission. Delivery of this message to any person other than the intended recipient is not intended to waive any right or privilege. If you have received this message in error, please promptly notify the sender and immediately delete this message from your system.
If you don't wish our future news letter, pls send address to ttickmay@aliyun.com for removal.
I'm only reproducing this because of the disclaimer. Really? You're fishing for clients, not giving legal, medical or confidential information. It doesn't mean a thing. Also, when I tried searching for this, Google helpfully mentioned:
Did you mean: This e-mail message and its attachments (if any) are intended solely for the use of the addressee(s) thereof. In addition, this message and the attachments (if any) may contain information that is confidential, privileged and exempt from disclosure under ap…
Heh.
Also, that text shows up on a lot of emails. A lot.
I would like to note that this came from 135328.com
,
a domain registered in China,
from a server in Williamsville, NY.
The email was from yjonjens@mail.com
,
which is from a domain registered to a company in Chesterbrook, PA and administered by a German company in Karlsruhe.
The default Reply-To:
address is broling@aliyun.com,
which is from a copmany in China registered by what appears to be either a European or American.
And as you can see,
it doesn't match the “sender” address,
nor the address mentioned in the email itself.
I'm not worried about being sued by these jokers.
Friday, April 24, 2015
Notes about a Lua lint checker
Luacheck is a static analyzer and a linter for Lua. Luacheck detects various issues such as usage of undefined global variables, unused variables and values, accessing uninitialized variables, unreachable code and more.
The one real issue I have with Lua is its dynamic typing. Of all the bugs I fix in my own Lua code, I would say that the majority are due to typos (wrong variable name) or an unexpected type. So I was quite happy to come across and try out Luacheck. And fortunately, it's pretty straightforward to run.
I ran it over “Project: Sippy-
Cup” and … wow. The extensive regression test I have has already flushed
out the typos and the unexpected type errors I tend to make. But Luacheck
found quite a few unused variables (which is nice—it also found a bunch of
unsused LPeg expressions) and a ton of unintentional
global variables (because I forgot to declare them with
local
).
The output is easy to read (here's a representative sample from some non- work related code I have):
Checking ptest-cr-select.lua Failure ptest-cr-select.lua:53:9: variable amount was previously defined as an argument on line 52 ptest-cr-select.lua:128:9: variable okay is never accessed ptest-cr-select.lua:193:40: unused argument event ptest-cr-select.lua:197:43: shadowing upvalue conn on line 194 ptest-cr-select.lua:213:21: shadowing upvalue argument event on line 193 ptest-cr-select.lua:215:15: unused variable rem ptest-cr-select.lua:215:15: shadowing upvalue rem on line 194 Total: 7 warnings / 0 errors in 1 file
About the only false positive it finds is this idiom:
function foo(param1,param2) local param1 = param1 or "default value" local param2 = param2 or 3 local a = ... -- ... end
where it will flag param1
and param2
as
shadowing an upvalue. This idiom though, is used to provide a default value
if a parameter isn't given to a function. It's easy enough to fix,
either:
function foo(param1,param2) param1 = param1 or "default value" param2 = param2 or 3 local a = ... -- ... end
or
function foo(param1,param2) local param1 = param1 or "default value" -- luacheck: ignore local param2 = param2 or 3 -- luacheck: ignore local a = ... -- ... end
Overall, I'm glad I found this tool. It's been a real eye opener.
Saturday, April 25, 2015
Jamie and Adam Unleased.
Bunny and I just saw Jamie & Adam UNLEASHED at the Kravis Center.
What a fun show.
Adam and Jamie would select crash test dummies victims volunteers
(and there were no shortage of thoses)
to come up on stage to help demonstrate some principle of physics,
such as a nine year old girl lifting two grown men a foot above the stage,
or arranging four men in a sitting position without chairs,
and other physics-based tricks.
They also talked about several myths they've done on their show Mythbusters which included lots of explosions. A lot of explosions. Including a several minute clip of various things they've exploded over the years (like water heaters, cars, buildings, cement trunks, more cars and in general, nearly every type of explosive device you can conceive of) that nearly brought down the house (literally, since they boosted the base so you could feel the explosions rattling the theater).
And to end the show, they shot a volunteer with a paintball gatling gun for what seemed like a solid minute (don't worry—the volunteer was wearing the suit of armor Adam wore to protect him underwater from sharks) leaving one paint covered volunteer and a volunteer shaped space on the wall behind him.
Very amusing stuff.
But I think the most amusing thing to happen at the show happened during intermission. I received the following text message:
I didn't recognize the number, and it took me a few moments to decide to even answer “Yes.” The response to my response was classic, and indeed, when I looked to my right, I saw my old roommate Rob, his wife Laura, Squeaky and his wife Tanya, sitting at the other end of the aisle.
'Tis a small world indeed.
Sunday, April 26, 2015
Just a quick note on something I noticed going on today on the home network
The script kiddies are active tonight.
Chain ssh-block (1 references) pkts bytes target prot opt in out source destination 17 1812 REJECT all -- * * 188.135.202.39 0.0.0.0/0 reject-with icmp-port-unreachable 38 2272 REJECT all -- * * 113.106.85.23 0.0.0.0/0 reject-with icmp-port-unreachable 4 348 REJECT all -- * * 117.253.105.235 0.0.0.0/0 reject-with icmp-port-unreachable 19 2080 REJECT all -- * * 37.190.87.219 0.0.0.0/0 reject-with icmp-port-unreachable 20 2316 REJECT all -- * * 187.72.49.52 0.0.0.0/0 reject-with icmp-port-unreachable 16 1796 REJECT all -- * * 201.75.109.180 0.0.0.0/0 reject-with icmp-port-unreachable 512 25388 REJECT all -- * * 218.83.6.81 0.0.0.0/0 reject-with icmp-port-unreachable 20 2248 REJECT all -- * * 177.70.122.255 0.0.0.0/0 reject-with icmp-port-unreachable 15 1800 REJECT all -- * * 117.253.215.122 0.0.0.0/0 reject-with icmp-port-unreachable 17 2032 REJECT all -- * * 117.244.25.226 0.0.0.0/0 reject-with icmp-port-unreachable 18 2048 REJECT all -- * * 134.255.165.240 0.0.0.0/0 reject-with icmp-port-unreachable 17 1964 REJECT all -- * * 187.49.248.42 0.0.0.0/0 reject-with icmp-port-unreachable
These are just the script kiddies caught trying to brute force a login to my home machine over the past hour (they're blocked after five attempts, and the block remains for an hour lest I end up with hundreds of entries). I wonder if there's a quota they have to meet?
Monday, April 27, 2015
A shot to the arm
I sit down. As soon as I do, the phlebotomist drops a padded bar across the seat. Sure, they claim its for resting your arm while they draw blood, but it's real purpose is to keep people from escaping. Most people don't hear the soft click as it's locked into position.
Then my arm is wrapped with a large rubber band, cutting circulation to my hand. Again, the claimed reason is to help a vein rise to the surface of the arm, but in reality, it's there to weaken the arm so you can't fight.
I'm surprised that I'm letting them do this to me. There must be something in the air to keep me docile throughout the procedure.
“This won't hurt a bit.” A lie. Not quite as bad as “the check is in the mail,” or “I'm from the government, I'm here to help,” but it's still a lie.
“Aaaaaaaaaaaaaaaaaiiiiiiiiiiiiiiiiieeeeeeeeeeaaaaaarrrrrrrrrrrrrrg!”
“I haven't started yet.”
“Just pract—aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah!”
“Just a few moments more.”
“Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahhhhhhhhhhhhhhhhhhhhhhhhhh!”
“Be patient.”
“Errrrrrrrrrrrrr—are you a phlebotomist, or a vampire?”
“That remark cost you three more vials.”
“Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrreeeeeeiiiiiiii!”
“There we go, that wasn't so bad, was it?”
“Aaaaaaaaaaaaaaaaaaaaaaaaaah!”
“The needle is out.”
“Aaaaaaaaaaaa—oh.”
“Here, hold this cotton pad here.”
I reach over with my other, non-blood-starved hand and place it over the cotton pad to staunch the flow of blood. The phlebotomist then tapes the cotton pad and my hand to my arm. “Um, you taped my hand to my arm.”
A very subtle click as the bar across the chair is lifted. “You are free to go.”
“Um. My hand is still taped to my arm.”
“Just pull it off. It won't hurt.”
Tuesday, April 28, 2015
Breaking Brain
Everybody knows how to ride a bike, right? But not everybody unlearns how to ride a bike. But Destin Sandlin did just that (link via Jason Kottke and no, it did not involve injury or a rare disease—he did this intentionally). He also untaught his six-year old son, who proved more adaptable because he was younger.
So, how do you unlearn riding a bike? Well, first off, you get a bicycle that steers backwards …
Wednesday, April 29, 2015
Alien packets from outer space
To help test “Project: Sippy-Cup,”
I wrote a mock component to return precanned data releated to our test data.
The mock component is basically a specialized DNS server that only expects a certain type of query.
I wrote it so it would be easier to configure and run than a full blown bind
installation.
But for the past few weeks it was crashing and pretty much the only report I would get back is “it crashed.” Sigh. I did find the error path in the mock component to be a bit spotty, but this was never intended to be a full blown product but rather something that would work just well enough to get the testing done. I never tested it with bogus queries because I never expected it to get bogus queries. We had control over all the data. The mock component would only talk to programs we were testing.
Even after fixing some “how did I not see that error?” type problems, the mock component was still crashing, and the only way that could happen is if the queries being sent were too large (over 512 bytes), the query was corrupted or malformed and could not be decoded, or if the query wasn't the single query type supported by the mock component. And there was no way any of that could happen. We controlled all the data!
Or so I thought.
It turns out the mock component was receiving God knows what from random computers on the Internet, which is incredible when the computer the mock component is running on doesn't have a public IP address!
Well, okay, it does have a public address, but it's a public IPv6 address, but the queries causing the crashes were all coming from IPv4 addresses.
Wow.
About the only thing I got to explain that behavior is the IPv6 address is routed via a tunnel, and perhaps there's some routing leakage that lets public IPv4 packets through. Other than that, I got nothing.
At the very least, I did fix the dodgy error handling so the mock component doesn't crash from data that it shouldn't get.
A trip to the hospital
Bunny was in the process of cutting up an old computer desk on the back porch with a sawzall when a chunk fell off in such a way not to break her big toe, but rip the nail off of it (ugh).
She managed to bandage it up and off we headed to the non-emergency emergency room at the local hospital. Bunny said it was more of a clinic than an emergency room but that it happens to be located in the emergency room.
Ooookay.
I drop her off, then spent the next ten minutes trying to locate the parking lot. Turns out that at the Boca Raton Regional Hospital, the emergency room parking lot (as well as the non-emergency emergency room parking lot) was across the street, marked by a few tiny signs with a low albedo.
Oddly enough, the emergency room wasn't crowded, and thus non-emergency emerency room wasn't crowded. By the time I had arrived in person, Bunny was already in the bowels of the hospital being treated.
And I'm stuck in the waiting room watching “Jurassic Park III.”
Limping, but at home
A bunch of people got eaten. Sam Neil managed to escape being eaten. The dinosaurs still roam that Central American Island like they own the place or something. And Bunny finally limped out of the non-emergency emergency room.
One clunky foot brace, some good medicine, dinner from Denny's (slogan: “You never start out for us, but you'll always end up here”) and all is, mostly, right with the world.
Thursday, April 30, 2015
Some perils of handing signals in Lua
This is one of those “Oh, yeah, I didn't think that through, did I?” type of bug.
I wrote a signal module for Lua, which can handle both ANSI C and POSIX signals with largly the same API (the POSIX implementation one has some additional functions defined).
Handling signals in Lua is not that straightforward because of the nature of signals—you are effectively writting multithreaded code.
You just can't call back into Lua from the signal handler
(while the Lua VM has no static data and each Lua state is isolated unto itself,
two threads sharing a Lua state can lead to problemss).
The only Lua function you can safely call is lua_sethook(),
which can be used to stop the Lua VM at the next VM instruction
(it's typically used for debugging and signal handing).
This callback can then call back into Lua.
It is a bit convoluted
(the signal handler will call lua_sethook()
and return; the Lua VM will resume and then call the hook),
but it does allow you to write signal handlers in Lua:
signal.catch('windowchange',function() print("Wheeee! Our terminal just resized!") end)
and not have it blow up on you.
So, with that in mind, I give you this code:
local net = require "org.conman.net" local clock = require "org.conman.clock" local signal = require "org.conman.signal" local raddr = net.address("127.0.0.1",udp,'echo') local sock = net.socket(raddr.family,'udp') signal.catch('alarm',function() sock:send(raddr,tostring(clock.get())) end) clock.itimer(1) local previous = clock.get() while true do local _,data = sock:recv() local now = clock.get() if data then local zen = tonumber(data) print(string.format("%.7f\t%.7f",now - zen,now - previous)) previous = now end end
This is a UDP echo client program.
signal.catch()
handles the alarm signal (SIGALRM
) by sending a packet of data
(which is just the current time)
to the echo server.
clock.itimer()
informs the kernel to send the alarm signal once a second.
So once a second,
our program receives the alarm signal and sends the current time.
Then,
in an infinite loop,
we just wait for packets to arrive
(which should be the packets we sent to the echo server—they're “echoed” back to us)
and we calculate how long the packet took round trip and how long it was from the previous packet.
The output looks like:
0.0002971 1.0014961 0.0003922 0.9999950 0.0002851 0.9998930 0.0003171 1.0000319 0.0003910 0.9999740 0.0002551 0.9998641 0.0003359 1.0000808
The first column is the round trip time (in seconds) for the packet (around 3 to 4 ten thousandths of a second), and the second column is how long (in seconds) from the previous packet (a second, give or take a few ten thousandths).
But our call to sock:recv()
is interrupted by the alarm signal.
Unfortunately, one side effect of signals is that they will interrupt “long running” system calls,
which is almost always system calls dealing with I/O, such as read()
or write()
.
When such a call is interrupted,
the system call will return an error of EINTR
.
We can see this if we change the code a bit:
local net = require "org.conman.net" local clock = require "org.conman.clock" local signal = require "org.conman.signal" local errno = require "org.conman.errno" local raddr = net.address("192.168.90.118",'udp',22222) local sock = net.socket(raddr.family,'udp') signal.default('int') signal.catch('alarm',function() sock:send(raddr,tostring(clock.get())) end) clock.itimer(1) local previous = clock.get() while true do local _,data,err = sock:recv() local now = clock.get() if data then local zen = tonumber(data) print(string.format("%.7f\t%.7f",now - zen,now - previous)) previous = now else print(">>>",errno[err]) end end
and when we run it:
>>> Interrupted system call 0.0003049 1.0015509 >>> Interrupted system call 0.0002320 0.9998269 >>> Interrupted system call 0.0002131 0.9999812 >>> Interrupted system call 0.0001860 0.9999728 >>> Interrupted system call 0.0002639 0.9999781
With POSIX,
you can specify that for a given signal,
system calls are to be automatically restarted so you can dispense with EINTR
error handling.
And here's were we finally get to the “Oh, yeah, I didn't think that through, did I?” type of bug.
Not wanting the code to be interrupted by the alarm signal,
I changed the call to signal.catch()
so it would restart any system calls:
signal.catch('alarm',function() sock:send(raddr,tostring(clock.get())) end,'restart')
When I ran the code, I got nothing! There was simply no ouput happening. It caught me by surprise and it took me several minutes to figure out what was happening (or rather, what wasn't happening):
- We enter
sock:recv()
(a Lua function), which ultimately does a system call torecvfrom()
; - the alarm signal (
SIGALRM
) is raised; - the kernel iterrupts our current system call (
recvfrom()
) and calls the signal handler we installed; - the signal handler calls
lua_sethook()
so that the Lua VM (when it resumes) will be stopped and our Lua hook function (written in Lua) will execute; - the kernel then resumes the system call (
recvfrom()
) that was previously interrupted.
And thus we get to the punchline:
the Lua VM doesn't resume because we're still in a system call!
And thus,
the signal handler written in Lua is never called,
which doesn't send a packet,
because we're stuck in our system call (recvfrom()
) waiting for some data that will never arrive.
D'oh!
If the above code were written in C,
there would be no issue; clock_gettime()
and sendto()
(the system calls underlying the Lua functions clock.get()
and sock:send()
respectively)
are safe to call from a signal handler.
I may not have been able to safely convert the time to text (since snprintf()
—the only standard C function able to convert numbers to text,
isn't documented as being safe to call in a signal handler) but sending the raw binary values would be okay in that case.
But this isn't C, it's Lua. And what we have here is a type of leaky abstraction. That 20/20 hindsight is such a bastard.
Friday, May 01, 2015
Living with being dead
Most of the patients here have been diagnosed with garden-variety neurological disorders: schizophrenia, dementia, psychosis, severe depression, or bipolarism. But the ones I am searching for are different. They suffer from an affliction even more puzzling: They believe that they are dead.
It’s a rare disorder called Cotard’s syndrome, which few understand. For patients who have it, their hearts beat and lungs pump, yet they deny their existence or functionality of their bodies, organs or brains. They think their self is detached.
Via Hacker News, Living With Being Dead — Matter — Medium
I would like to congratulate Sean Hoade on his Zombi epalooza interview, and what better way to do that than to link to an article about people who think they're dead. Does that mean they think they're zombies? Or ghosts? Or just dead and their body has yet to notice?
Saturday, May 02, 2015
Borg
Sigh.
I hate web based applications, because as soon as you get used to the interface—BAM some attention-deficit programmers change how everthing works, just because. Google Maps is a good example of this. It's still perhaps the best mapping application out there and I always use it, but every few months they change how the entire interface works, destroying existing patterns of use and wasting days, nay weeks of time as I attempt to learn how to use the features I use, only to find out half of them have been removed, because.
Ahhhhhhhhh!
But today I'm not here to bury Google Maps, but Facebook. They broke my posting application. The application I use when I post to this blog and send notification to Facebook that is posted on my … whatever that thing is called at Facebook. My wall? Timestream? Spam channel? Whatever it's called.
Facebook changed how things work on the backend, and now I'm getting the dreaded 803 error (and of course there are no real answers there).
Thank you Facebook.
Thank you a lot.
Amoeba
It appears that Facebook wants to be the internet (much like Google in fact) or at the very least, force the impression that the web is Facebook. Why else make such a drastic change in API that disallows small blogging sites from updating Facebook remotely?
After spending several hours pouring over the Facebook API documentation, my eyes are glazing over and from what I can see, it appears Facebook only supports three use cases (aisde from using the Facebook website itself):
- an application running on Android;
- an application running on iOS;
- an application running on a website (preferrably using Facebook to authenticate the user).
And that last one—it's someone actively using the website.
My now-broken application?
That was kicked off when I posted to my blog
(most of the time that's via email,
where I can use an editor of my choice to compose the entry instead of whatever hideous crap editing you get in a TEXTAREA
on a webpage)
where I may or may not be logged into Facebook at the time
(usually not,
not that it matters at all for tracking purposes,
which is for another post).
And my application wasn't the only one Facebook broke.
And that appliation looks like it won't be fixed any time soon ever!
(sorry Dan)
So it looks like I'm stuck manually posting to Facebook when I update here. I was already updating GooglePlus manually because they have yet to provide an API to update remotely (I don't expect one any time soon). I suppose I could automatically update Twitter, which can update Facebook (now that I worked around the broken Twitter API—are you seeing a pattern here?) but there's no telling how long that will last; I'd be stuck with a 140 character limit including the link and well … no.
There's more to the web than just GoogleMyFacePlusSpaceBook, and long term, I think it'll be easier to just manually update FaceGoogleMyBookPlusSpace. XXXX the GoogleMyFaceSpaceBookTwitterPlus APIs. XXXX them all!
Update on Sunday, May 3rd, 2015 at 02:28 am
Petty, I know, but it made me feel better.
Sunday, May 03, 2015
When Las Vegas is not Las Vegas
Ah, Lost Wages. It's been a few years since my last visit, but each time I've been there, I technically wasn't in Las Vegas, but in Paradise. Paradise, Nevada to be precise.
And yes, it was a tax dodge.
Monday, May 04, 2015
Today my friends are talking with a lithp.
So … does this mean The Empire should have installed a cup on the Death Star?
May the Fourth be with you!
Tuesday, May 05, 2015
Ch-ch-ch-changes for the mobile web
It's been brought to my attention by a few parties that my blog was unviewable on some smartphones; which smartphones I don't know (but I suspect Android based devices). I finally got around to it and the changes were minimal. This:
<meta name="HandHeldFriendly" content="True">
(the Google Mobile-Friendly Test fell on the floor laughing when it encountered that line) changed to:
<meta name="viewport" content="width=device-width, initial-scale=1">
And that's it for the HTML changes. The CSS changes weren't that bad, once I figured out what was needed. I asked a fellow cow-orker, D, what I needed to do in order to serve up a “mobile-friendly CSS file” and his advice was: “Do whatever CNN does.”
Sigh.
It appears there is no real reliable way to detect a smartphone through CSS only. Sure, I could try to detect a smartphone by sniffing the user agent, but I wanted something easy, not something error prone despite a ton of ongoing configuration and testing. So that was out. And the obvious media query:
<link media="handheld" rel="stylesheet" href="/CSS/smartphone.css" type="text/css">
was right out because “smartphones” are “smart” and not at all a “handheld.” Sheesh.
I ended up doing what CNN did—base the style upon the width of the browser. It seems that a “safe” width for smartphones is around 736 pixels. Larger than that, and I can assume a real desktop (or laptop) display; that or less and hey, treat it as a smartphone. And if your browser window on the desktop (or laptop) is less than 737 pixels, you'll get the “mobile” version of my site.
Anyway, the changes weren't all that bad. The “not-main-content” is positioned via CSS and that's all I really wanted to change. For instance, I had this style for the main content:
/* Yes, the DIV is redundant. I left it in because I want to be explicit */ DIV#content { margin-top: 0; margin-bottom: 0; margin-left: 220px; margin-right: 180px; border: 0; padding: 0; }
To fix this for the smartphone:
DIV#content { margin-top: 0; margin-bottom: 0; margin-left: 220px; margin-right: 180px; border: 0; padding: 0; } /* override some previous settings for "smartphones" */ @media screen and (max-device-width: 736px), screen and (max-width: 736px) { DIV#content { margin-left: 0; margin-right: 0; } }
The rest of the changes were along those lines for the major portions of the page—override the placement settings for the various bits and pieces.
So now the blog should be readable on small devices.
I hope.
Driskell v. Homosexuals
It seems that one Sylvia Ann Driskell is suing homosexuals (link via Flutterby). The handwritten lawsuit is a riot to read, but ultimately, it does seem that Ms. Driskell might be in need of some mental care (if not a proofreader).
Also, I think that Ms. Driskell needs to read (or listen) to Matthew Vines' talk on the Bible and homosexuality (it's long, but I think it's worth the time if only for some Christians to gain some perspective, and for gays to get some counter arguments for the Westboro Baptist Churches out there).
Wednesday, May 06, 2015
Dogs and cats living together
I'm watching an animated interview of Buckminster Fuller when I see this sequence of equations:
a = b a2 = ab a2 - b2 = ab - b2 (a+b)(a-b) = b(a-b) a+b = b 2b = b 2 = 1
And I'm thinking, that looks right, as far as I can remember algebra, but two can't be equal to one, can it?
I had to work through it by hand to find the problem, and now, gentle reader, you get to work through it yourself.
You're welcome.
Thursday, May 07, 2015
Small websites need not apply
Hoade and I were exchanging emails about AdWords today. He's trying to get his writing career into overdrive, seeing how every other job he's tried never worked out. I advised him against AdWords unless someone else was footing the bill, as it can get expensive.
I've also heard first hand that AdWords wasn't worth the money spent on it.
On the flip side, I found that AdSense wasn't worth it for me. Sure, if my blog had a bit more focus, like I was writing about gendered bodies in Japanese pornographic anime and horror through a Foucauldian framwork in order to analyze the West's gaze upon the world, Google would have had a better time generating related advertising towards the blog, but alas, my blog isn't that focused and the ads I did get were bizarre. And it didn't help me that not many people were seeing the ads.
Things might have changed since my last experiment with AdSense (or what I heard about AdWords), but I still cautioned Hoade about wasting money on AdWords. I feel he would do better by getting his name out there on podcasts and web-based forums. At least that way, he won't spend any money.
Last words from Hoade:
Just to add a little coda to our AdWords / Facebook ads convo, the for-real serious consensus seems to be "Maybe it could work. Do some A/b testing with your massive pile of ad money. One way might could work gooder than another." Not even XXXXXXX kidding.
Actual quote: "She ended up with a 1.3 percent click-through rate, which is actually very good." I believe this is true, but lord, it doesn't make you run for your checkbook.
Yeah, I'm thinking small sites need not apply.
Friday, May 08, 2015
I, for one, welcome our new self-driving robotic overlords
As I thought about Google's self-driving car, I realized that more than just taxicab drivers should be worried—there would be tremendous pressure from the trucking industry (and I'm not talking about the drivers here) to allow driverless trucks on the road. I'm not terribly surprised.
License plates are rarely an object of attention, but this one’s special the funky number is the giveaway. That’s why Daimler bigwig Wolfgang Bernhard and Nevada governor Brian Sandoval are sharing a stage, mugging for the phalanx of cameras, together holding the metal rectangle that will, in just a minute, be slapped onto the world’s first officially recognized self-driving truck.
The truck in question is the Freightliner Inspiration, a teched-up version of the Daimler 18-wheeler sold around the world. And according to Daimler, which owns Mercedes-Benz, it will make long-haul road transportation safer, cheaper, and better for the planet.
“There’s a clear need for this generation of trucks, and we’re the pioneers who are willing to tackle it,” says Bernhard.
Via InstaPundit, The World's First Self-Driving Semi-Truck Hits the Road | WIRED
I am also reminded of Humans Need Not Apply, but it might be all that dire.
Saturday, May 09, 2015
The Dymaxion Car
The Dymaxion Car, designed by Buckminster Fuller. It wasn't pretty. It could seat eleven. It was difficult to drive. It killed one of its first drivers. But it got 30mpg and could travel at 90mph. Kind of a mixed bag for a car built in 1933.
Still, it might be somewhat fun to ride in it, as long as there's a trained driver.
Sunday, May 10, 2015
Eight years of greylisting
I've been hacking on my greylist daemon over the past few days.
I'm not sure what,
exactly,
prompted me to start hacking away at it though.
The last code change was in December of 2011—all code changes since then have been tweaks to the Makefile
(the file that describes how to build the program).
As I'm hacking on it,
I've come to hate the code handing the protocol the components use for communications
(there's the main component that manages the data and logic;
there's the component that interfaces with sendmail
and another one that interfaces with postfix
).
And over the past few days, I've reflected over what I would do differently if I were to write the greylist daemon now and how well my decisions eight years ago held up.
One decision I made eight years ago was to write my own “key/value” store instead of using a pre-existing one. I rejected outright the use of an SQL database engine (like MySQL or PostgreSQL) and I don't think I would change my mind now. The data stored is short lived (six hours for most entries, otherwise thirty-six days) and I don't think such churn is good for database engines.
In addition,
the only NoSQL based solution (as they're now called) at the time was memcached
(written in 2003; redis
wasn't released until 2009,
two years after I released the greylist daemon).
memcached
(and redis
) can expire entries automatically,
and it could handle five out of the six lookups the greylist daemon makes.
The one lookup neither one can handle
(as far as I can tell) is the IP address lookup.
This lookup compares the IP address of the sending SMTP server against a list. The list describes an address range and what to do if the given IP address “matches.” For example:
0.0.0.0/0 GREYLIST 205.211.164.50/32 ACCEPT 206.214.64.0/19 REJECT 207.115.11.0/26 ACCEPT
If, say, the IP address is 207.115.11.8, then the email is accepted and further processing is skipped because of the matching rule:
207.115.11.0/26 ACCEPT
An IP address of 206.214.64.10 is rejected, because of the matching rule:
206.214.64.0/19 REJECT
An address like 66.252.224.242 will match the rule
0.0.0.0/0 GREYLIST
and because the result is GREYLIST
,
futher checks are made.
There does not appear to be a way of handling this type of query using memcached
or redis
.
I would have to write code to store the IP addresses anyway.
Also,
memcached
is a pure memory cache—if it crashes,
all the data goes away
(and remember—at the time I wrote this,
this was really the only key/value store that existed that wasn't an SQL database engine)
which is something I didn't want to happen.
So my decision at the time to write my own key/value store wasn't a bad one.
Today?
Today I might consider using redis
to store what I could,
but it's another component that,
if it isn't available,
I can't greylist incoming email
(I have to allow the email in—fail safe and all that).
Also,
the code I wrote to store the non-IP address data was easy to write.
I dunno.
It's hard to say how I would store the data today.
The protocol between my components is something I would handle completely differently today. I can't say what the actual protocol would be though.
There are basically two methods of sending data—a series of values in a fixed order (which is how the protocol works today) or as a series of tagged values, which can appear in any order. The former doesn't really deal well with optional data (you end up tagging such values anyway) while the later is harder to parse (since the values aren't in a fixed order, you have to deal with missing values in addition to duplicate values).
The biggest issue I have with the protocol now is what I said above, the code that handles the protocol is a mess—it's all over the place instead of in a few isolated routines. That makes updating the protocol (say, adding new fields, fixed or optional) very difficult.
What I would do now is make the protocol handing portion more of a module—a module for version 1.0 of the protocol, a module for version 1.1 of the protocol, etc., load them all up, and based upon the version embedded in the packet (something I do have, by the way), farm out the processing to the proper protocol version module. It would make updating the protocol easier to deal with in the codebase. The lack of this approach to the protocol is, I think, the biggest problem with the codebase today.
One last aspect I would change is the logging of verious statistics,
or “key performance indicators” as they are called in the industry.
Instead of incrementing a bunch of variables in the codebase and every so often dumping them out to syslog
(messy code requiring the use of signals and all the problems that entail,
and several lines of code modified for every new KPI added)
I would use the method they use at Etsy—statsd
—or at least,
my own take on it.
I don't need the full blown “all-singing, all-dancing, all-graphing” statsd
that Etsy developed but one that just logs to syslog()
.
And given the whole concept is easy,
a small version that just logs to syslog()
is pretty trivial to write
(I wrote a version in Lua with 225 lines of code,
and a full quarter of that is just parsing the command line).
The nice thing about a statsd
-like concept is that it is trivial to add new KPIs to the codebase,
and they're logged automatically without any other changes.
The logging and potentially resetting of values is all isolated in statsd
,
in the way that log messages are logged to files or forwarded to another server is isolated in syslog
.
There's not anything else I would really modify in the greylist daemon. Really, the only bad decision I made eight years ago was not fully isolating the protocol. Everything else was an okay decision.
And frankly, I'm not even sure if the greylist daemon needs any more work done on it.
Monday, May 11, 2015
SPF might not be worth handling, but what about RBL?
A month ago, I re-evaluated the use of SPF as an anti-spam measure and found it wanting. Today, I decided to re-evaluate my stance on the various real-time blackhole lists that exist. I was relunctant to use an RBL because of over-aggresive classification for even the smallest of infractions could lead to false positives (wanted email being rejected as spam). It has been over a decade since I first rejected the idea, and I was curious to see just how it would all shake out.
I used the Wikipedia list of RBLs as a starting point, figuring it would be pretty up-to-date. I then dumped information from my greylist daemon. The idea is to see how much additional spam would be caught if, after getting a “GO!” from the greylist daemon, I do a RBL check.
Out of the current 2,830 entries, only 145 had not been whitelisted. I didn't filter these out before running the test, but I don't think it would throw off the results too much. Half an hour of coding later, and I had a simple script to query the various RBLs for each unique IP address (1,446). I let it run for a few hours, as it had quite a few queries to make (1,446 IP addresses, each one requiring one query to see if the IP address is a known spammer, and a possible second one for the reason, across 45 RBL servers—it took awhile).
First up, how many “spam” results did I get from each RBL:
RBL | hits | reasons given |
---|---|---|
truncate.gbudb.net. | 108 | 108 |
dnsbl.proxybl.org. | 0 | 0 |
dnsbl-1.uceprotect.net. | 132 | 132 |
dnsbl-2.uceprotect.net. | 145 | 145 |
dnsbl-3.uceprotect.net. | 23 | 23 |
dnsbl.sorbs.net. | 65 | 65 |
safe.dnsbl.sorbs.net. | 65 | 65 |
http.dnsbl.sorbs.net. | 0 | 0 |
socks.dnsbl.sorbs.net. | 0 | 0 |
misc.dnsbl.sorbs.net. | 0 | 0 |
smtp.dnsbl.sorbs.net. | 0 | 0 |
web.dnsbl.sorbs.net. | 21 | 21 |
new.spam.dnsbl.sorbs.net. | 37 | 37 |
recent.spam.dnsbl.sorbs.net. | 184 | 184 |
old.spam.dbsbl.sorbs.net. | 0 | 0 |
spam.dbsbl.sorbs.net. | 0 | 0 |
escalations.dbsbl.sorbs.net. | 0 | 0 |
block.dnsbl.sorbs.net. | 0 | 0 |
zombie.dbsbl.sorbs.net. | 0 | 0 |
dui.dnsbl.sorbs.net. | 0 | 0 |
rhsbl.sorbs.net. | 0 | 0 |
badconf.rhsbl.sorbs.net. | 0 | 0 |
nomail.rhsbl.sorbs.net. | 0 | 0 |
sbl.spamhaus.org. | 293 | 293 |
xbl.spamhaus.org. | 53 | 53 |
pbf.spamhaus.org. | 0 | 0 |
cbl.abuseat.org. | 36 | 37 |
psbi.surriel.com. | 0 | 0 |
intercept.datapacket.net. | 186 | 186 |
db.wpbi.info. | 0 | 0 |
bl.spamcop.net. | 65 | 65 |
noptr.spamrats.com. | 224 | 224 |
dyna.spamrats.com. | 208 | 208 |
spam.spamrats.com. | 15 | 15 |
bl.spamcannibal.org. | 96 | 96 |
spamtrap.drbl.drand.net. | 0 | 0 |
blacklist.hostkama.com. | 0 | 0 |
dnsbl.dronebl.org. | 2 | 2 |
list.quorum.to. | 1309 | 1309 |
ix.dnsbl.manitu.net. | 48 | 48 |
dnsbl.inps.de. | 627 | 627 |
bl.blocklist.de. | 6 | 6 |
srnblack.surgate.net. | 21 | 21 |
all.s5h.net. | 363 | 363 |
rbl.megarbl.net. | 54 | 54 |
As you can see,
some of them were not worth querying.
Also,
about list.quorum.to
…
it's not straightforward to use that server
as it always sent back a result even when the others did not.
I ultimately decided that any result that only had a “hit” from list.quorum.to
to be “non-spam” because of the issues.
I then proceeded to pour through all 2,830 results.
Marked as SPAM | 2739 | 97% |
---|---|---|
Not marked as SPAM | 91 | 3% |
Total | 2830 | 100% |
And out of the 91 that was not marked as spam, only 7 were spam not marked by any of the RBLs. Not bad. But the real test is false positives—email marked as spam that isn't. And unfortunately, there were a few:
bounce.twitter.com | 10 |
icpbounce.com | 2 |
bounce.linkedin.com | 3 |
returns.groups.yahoo.com | 8 |
facebookmail.com | 6 |
Total | 29 |
Now, I realize that some of my readers might very well consider email from Twitter or Facebook as spam, but hey, don't judge me!
Ahem.
Anyway, that's a problem for me. I will occasionally have issues with the greylisting in some cases (rare, but it does happen, and I have to explicitely authorize the email when I become aware of the issue) but it's even worse with this. For instance:
66.220.155.148 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.151 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.143 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.136 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | FAIL | ix.dnsbl.manitu.net. | |
66.220.155.172 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.140 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.142 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | FAIL | intercept.datapacket.net. | ix.dnsbl.manitu.net. |
66.220.155.144 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | FAIL | ix.dnsbl.manitu.net. | |
66.220.155.137 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | FAIL | recent.spam.dnsbl.sorbs.net. | ix.dnsbl.manitu.net. |
66.220.155.141 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | FAIL | dnsbl.dronebl.org. | ix.dnsbl.manitu.net. |
66.220.155.147 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.152 | notification+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.152 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! | ||
66.220.155.150 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | FAIL | ix.dnsbl.manitu.net. | |
66.220.155.138 | update+iedcilif@facebookmail.com | XXXXXXXXXXXXX@conman.org | GO! |
It's hit-or-miss within the IP range Facebook uses to send email. This would make troubleshooting quite difficult. I could whitelist the problematic domains but for any new site I might want to receive email from, I would have to watch the logs very closely for issues like this. But it's not as bad as I thought it would be, and it would cut out a lot of the spam I do get. It's tempting.
I shall have to think about this.
Tuesday, May 12, 2015
He is the electric messiah! The AC/DC god!
Today we received an email from the Marketing Department of the Corporation Overlord Corporation touting their latest press release to the public. They linked to the press release at the various GoogleMyFacePlusTwitterSpaceBook sites using some outrageous graphics. The one for Facebook was pretty scary looking, being based on this:
Image by Charis Tsevis
I'm not sure why the Marketing Departmemt of the Corporation Overlord Corporation felt the standard linking images for FaceTwitterGoogleMyPlusSpaceBook weren't good enough and needed to “kick it up a notch,” but there you go.
But as a counter point to that (or maybe even a counter-counter point, or a point, or something), here's an interesting video (warning: it's an hour) on the digital tracking that MyFaceGoogleSpaceBookPlusTwitter can (and most likely, is doing), if you can stomache the whole “viva la revolución my democratic comrades” vibe the speaker gives off (and you can pretty much skip the last fifteen to twenty minutes where it gets really thick).
Wednesday, May 13, 2015
Notes on an overheard conversation at The Ft. Lauderdale Office of The Corporation
“Can you help me?”
“Sure. What's the problem?”
“When I'm logged into my laptop as me, I can run ispell
. But if I switch to root
, it's not there.”
“Hmm … where does ispell
live?”
“It's in /usr/local/bin
. And before you ask—I checked, /usr/local/bin
is in root
's $PATH
.”
“Hmmm … I'm running … um … that version of the operating system.”
“Rabid Wombat? I am too.”
“Let me drive the laptop for a second.”
“Okay. These two terminal windows.”
“Can you switch to root
for me?”
“There you go.”
“Now, let's see … as you, I can see ispell
in /usr/local/bin
and the permissions seem okay. Now in the root terminal window … wow! There's a completely different set of files in /usr/local/bin
. Hmmm … ”
“Any ideas?”
“Wait a second … that root window is on another system!”
“Oh … that would explain my problem … ”
“Yes it would.”
Thursday, May 14, 2015
The Flying Camera
I have a soft spot for cameras. I've got a few 35mm cameras, a couple of 8mm cameras and floating around here somewhere is a Super-8 camera. I also have … um … I think three, maybe four, digital cameras (which includes the one in my iPhone).
So yeah, I like cameras.
And even with my current crop of seldom-used cameras, I want the Lily (link via MyFaceTwitterGoogleSpaceBookPlus). The camera you toss in the air and it follows you around.
It's probably for the best that you can only pre-order the thing for now. And I live less than a mile from an airport.
Sigh.
Friday, May 15, 2015
Countrly Road
For no good reason, here's a video of some Japanese musicians doing a cover of John Denver's “Take Me Home, Country Raod” (link via Instapundit).
Saturday, May 16, 2015
The more things change
So.
HTTP2 is finally here (link via Hacker News). I'm not happy about it, but what can I (or you) do? It's a done deal.
Part of the reason I don't like it is that it seems as if Google pushed this for their own needs.
You have a completely warped perspective here.
This is something Google pushed, so that Google can have as many tracking cookies as they like when you browse the internet, without the cookies causing a noticeable performance degradation because a http request might exceed the American DSLs MTU size.
This was one of the primary engineering criterias. No really.
There's no features in it for the user.
You have a completely warped perspective here. This is something Google pushed,… | Hacker News
Google is now in a position to dictate the architecture of the web. Sure,
one could ignore Google and blithely go about their web business, but really,
if you want to even have a chance of being found on the web, you follow
the dictates commands of Google! Heck, even I kept
mucking with my blog until I got the “okay”
from Google (although there
were other reasons I did the change besides Google, notice I didn't stop
until Google said I was okay). And don't think Google will stop
there (which is another rant for another time).
Another reason I don't like HTTP2 is that, as written, it's TCP over TCP. I can understand why they did it that way, but it's sad that for as much power as Google has, even they couldn't force a more sensible change.
Sigh.
Plus ça change, plus ils deviennent énervant.
Sunday, May 17, 2015
The blind men and the Molochian elephant
Bostrom makes an offhanded reference of the possibility of a dictatorless dystopia, one that every single citizen including the leadership hates but which nevertheless endures unconquered. It’s easy enough to imagine such a state. Imagine a country with two rules: first, every person must spend eight hours a day giving themselves strong electric shocks. Second, if anyone fails to follow a rule (including this one), or speaks out against it, or fails to enforce it, all citizens must unite to kill that person. Suppose these rules were well-enough established by tradition that everyone expected them to be enforced.
So you shock yourself for eight hours a day, because you know if you don’t everyone else will kill you, because if you don’t, everyone else will kill them, and so on. Every single citizen hates the system, but for lack of a good coordination mechanism it endures. From a god’s-eye-view, we can optimize the system to “everyone agrees to stop doing this at once”, but no one within the system is able to effect the transition without great risk to themselves.
And okay, this example is kind of contrived. So let’s run through – let’s say ten – real world examples of similar multipolar traps to really hammer in how important this is.
Meditations On Moloch | Slate Star Codex
I don't agree with everything said in this long article (and warning—it is long. I mean, long. Did I mention just how long it was?) but I do feel that certain someones would benefit greatly if they read it and thought long and hard about it. While I'm tempted to give my summary of the article I'd rather not, lest my intended target audience disreguard the article entirely.
Monday, May 18, 2015
Gaming the system
By December 2011, lajello’s profile had become one of the most popular on the entire social network. It had received more than 66,000 visits as well as 2435 messages from more than 1200 different people. In terms of the number of different message received, a well-known writer was the most popular on this network but lajello was second.
Only lajello isn't a human, but a spambot, but using the information in the article to boost your own ranking on MyFaceGoogleSpaceBookPlusTwitter is left as an exercise for the reader.
Tuesday, May 19, 2015
Wishful thinking
There are times when I wish the RFCs had more examples that covered various corner cases, such as handling SMTP or even, you know, SIP!
Ahem.
Anyway, while I'm here, let me also ask for a way to log everything but only when something is going to fail and skip the logging for stuff that won't fail (that just wastes space). How hard can that be?
Wednesday, May 20, 2015
If you think signal handling in C sucks, try Lua
So I have this Lua module to handle signals I wrote …
Originally, I just set a flag that had to be manually checked, as that was the safest thing to do (make that “practically the only thing you can do” if you want to be pedantic about it).
But after a while,
I thought it would be nice to write a handler in Lua and not have to manually check a flag.
Unfortunately,
signal handlers have to be thought of as asynchronous threads that run at the worst possible time,
which means calling into Lua from a signal handler is … not a good idea.
The way to handle this is to hook into the Lua VM in the signal handler.
lua_sethook()
is the only safe Lua function to call from an asynchronous thread
(or signal handler)
as it just sets a flag in the Lua VM.
Then when the Lua VM is at a safe spot,
the hook is call which can then run the Lua function.
So we write our Lua function:
function Lua_signal_handler() print("Hi! I'm handing a signal!") end
and here I'm making it a global function just for illustrative purposes. At some point, we catch the signal to install the signal handler (which has to be in C):
/*------------------------------------------------------------------------ ; In order to hook the Lua VM, we need to statically store the Lua state. ; That's what this variable is here for ... ;-----------------------------------------------------------------------*/ static lua_State *gL; /* ... code code blah blah ... */ /*---------------------------------------------------------------- ; we're in some function and we have access to a Lua state. Store ; it so the signal handler can reference it. ;----------------------------------------------------------------*/ gL = L; /*--------------------------------------------------------------- ; sigaction() should be used, but that's quite a bit of overhead ; just to make a point. Anyway, we are installing our signal ; handler. ;--------------------------------------------------------------*/ signal(SIGINT,C_signal_handler);
The signal handler installs a hook:
static void C_signal_handler(int sig) { lua_sethook(gL,luasignalhook,LUA_MASKCALL | LUA_MASKRET | LUA_MASKCOUNT,1); }
and when it's safe for the VM to call the hook, it does, which then calls our signal handler written in Lua:
static void luasignalhook(lua_State *L,lua_Debug *ar) { /*------------------------------------------------------------------ ; remove the hook as we don't want to be called over and over again ;------------------------------------------------------------------*/ lua_sethook(L,NULL,0,0); /*-------------------------------------------------------------------------- ; get our function (which is a global, just for illustrative purposes, and ; call it. ;--------------------------------------------------------------------------*/ lua_getglobal(L,"Lua_signal_handler"); lua_call(L,1,0); }
Yes, it's a rather round-about way to handle a signal, but that's what is required to run Lua code as a signal handler. And it works except for two cases (that I have so far identified—there might be more).
The first case—coroutines. Lua coroutines can be thought of as threads, but unlike system threads, they have to be scheduled manually. And like system threads, signals and coroutines don't mix. Each coroutine creates a new Lua state, which means that if a signal happens, the Lua state that is hooked may not be the one that is currently running and thus, the Lua-written signal handler may never be called!
The second issue involves a feature of POSIX signals—the ability to restart system calls. Normally, a signal will interrupt a system call and its up to the program to restart it. There is an option to restart a system call automatically when a signal happens so the program doesn't have to deal with it. The funny thing is—under the right conditions, the Lua signal handler is never called! Say the program is making a long system call, such as waiting for a network packet to arrive. A signal is raised, our signal handler is called, which hooks the Lua VM. Then the system call is resumed. Until a packet arrives (and thus we return from the system call) the Lua VM never gets control, and thus, our function to handle the signal is never called (or called way past when it should have been called).
Fortunately, I found these issues out in testing, not in production code. But it has me thinking that I should probably work to avoid using signals if at all possible.
Thursday, May 21, 2015
Notes about an overheard conversation at The Ft. Lauderdale Office of The Corporation
“We should definitely do that at Black Hat!”
“I didn't know you were into haberdashery.”
“What?”
“I think you mean millinery. Haberdashers generally sell buttons and thread and stuff.”
“Really?”
“Yes.”
“What are you guys talking about?”
“Your fascination with hats.”
“You mean Black Hat?”
“Yeah. Haberdashery.”
“Millinery!”
“Oh, sorry. Millinery.”
“You guys are crazy.”
“We're just pushing it to eleven.”
The check that was in the mail
I'm checking my snail mail and … what's this? A check?
You mean the check was in the mail?
Oh wait … it's one of those “promotional checks” and not a “real check,” even though it has a check number, it's made out to me, has the value as both numbers and words, it's signed, and has what look to be a routing number (to an Australian bank‽) and account number. Also, across the bottom it has: “THIS DOCUMENT CONTAINS A BLUE BACKGROUND, [Check! –Sean] MICROPRINTING [Oh yes, it does. It doesn't make much sense, but I can make out the letters. —Sean] AND AN ARTIFICIAL WATERMARK ON THE BACK [Yup, “IPS.” So, check! —Sean] — VOID IF NOT PRESENT” [Nope, it's all there, so it's not void. —Sean]
And there is the story of man who deposited a “promotional check” for $95,000 …
So maybe it's a real check?
Perhaps I could try depositing it? [No! —Bunny] [Awwww! —Sean] [Okay, it's your bank account to lose … go right ahead! —Bunny] [Woot? —Sean]
Friday, May 22, 2015
“Consistent mediocrity, delivered on a large scale, is much more profitable than anything on a small scale, no matter how efficient it might be.”
Fundamentally, there’s a theme in Olia’s speech (and the speech of others in that space, like Dragan Espenschied, Ben Fino-Radin, and so on) bemoaning the move away from a space on a website being the province of the users, and being turned into a homogenized, commodified breeder farm of similar-looking websites with only surface implementations, like WordPress, Facebook Pages, and so on.
…
There was a time when a person who was not particularly technical, or whose technical acumen was sufficient to get applications running on a machine and not much more, could code a webpage. The tags were pretty straightforward, the uses of them clear, and the behavior pretty dependable. Much how one could, in a weekend, learn sufficiently how to pilot a sailboat… such was that a few weekends of study could allow a person to craft a fun little webpage, with their voice, their stamp, and the idiosyncrasies of their personality shining through.
Those days are gone. Long gone.
Instead, we have this (as my buddy Ted Nelson calls it) nightmare honky- tonk of interloping, shifting standards soirees that ensure, step by step, bylaw by beta, that anybody who isn’t willing to go full native will be shut out forever. The Web’s underpinnings, at least on the basic HTML level, have been given over to the wonks and the engineers, making it an impenetrable layer of abstraction, not worth your time to learn unless you were looking to buff up your resume, or if some programmer pride resided in this whole mess being in your job description.
That Whole Thing With Sound in In-Browser Emulation « ASCII by Jason Scott
There's no need to read the full article (unless you are interested in the state of audio in webpages and how it's not serving web based emulators of old home computers letting people play thousands of games from the 80s and 90s); I'm just quoting the part that spoke to me.
I'm also reminded of this:
For a very long time, taste and artistic training have been things that only a small number of people have been able to develop. Only a few people could afford to participate in the production of many types of media. Raw materials like pigments were expensive; same with tools like printing presses; even as late as 1963 it cost Charles Peignot over $600,000 to create and cut a single font family.
The small number of people who had access to these tools and resources created rules about what was good taste or bad taste. These designers started giving each other awards and the rules they followed became even more specific. All sorts of stuff about grids and sizes and color combinations — lots of stuff that the consumers of this media never consciously noticed. Over the last 20 years, however, the cost of tools related to the authorship of media has plummeted. For very little money, anyone can create and distribute things like newsletters, or videos, or bad ass tunes about "ugly."
Suddenly consumers are learning the language of these authorship tools. The fact that tons of people know names of fonts like Helvetica is weird! And when people start learning something new, they perceive the world around them differently. If you start learning how to play the guitar, suddenly the guitar stands out in all the music you listen to. For example, throughout most of the history of movies, the audience didn't really understand what a craft editing was. Now, as more and more people have access to things like iMovie, they begin to understand the manipulative power of editing. Watching reality TV almost becomes like a game as you try to second-guess how the editor is trying to manipulate you.
As people start learning and experimenting with these languages authorship, they don't necessarily follow the rules of good taste. This scares the shit out of designers.
In Myspace, millions of people have opted out of pre-made templates that "work" in exchange for ugly. Ugly when compared to pre-existing notions of taste is a bummer. But ugly as a representation of mass experimentation and learning is pretty damn cool.
Regardless of what you might think, the actions you take to make your Myspace page ugly are pretty sophisticated. Over time as consumer-created media engulfs the other kind, it's possible that completely new norms develop around the notions of talent and artistic ability.
Happy Ugly.
But sadly, no one cares.
Saturday, May 23, 2015
Sometimes, you just gotta go back to the 8-bit era
In the pages that will follow, I will be documenting the various stages in the design of a new arcade game that I hope to create for my classic Tandy Color Computer 3 sold internationally by the Radio Shack Corporation during the 80's and early 90's. This game will largely be created the old school way utilizing as much as possible the same setup that I used to develop games back then.
As a teenager with a computer during the 80s I always had the idea of writing a computer game in the back of my mind, but I never did know how to write one. It perhaps didn't help that I had a Tandy Color Computer at the time. I know, it's a bad craftsman that blames his tools, but in this case, I think there's something to it. The Color Computer had no hardware graphics to speak of (the Color Computer 3 did, but I had moved on to the PC world by the time it came out) so it was up to the programming to do all the bit shifting, masking and drawing which isn't as easy as it sounds (or rather, making it fast isn't that easy).
I never did write a game.
But it is a simple computer. Unlike modern systems, the entire computer is documented in a 70-page book and games were written for it. So feeling a bit nostalgic, I fired up an emulator (I'm nostalgic, not masochistic) and spent a few hours getting a simple graphic program going.
Yeah, not that easy. That running man? (bonus points if you recognize where he comes from) There're eight images in the animation, and each image is repeated four times, each one shifted right one pixel to avoid having to do a massive amount of shifting at runtime (it's a classic “memory vs. time” tradeoff here). Then I had to align the images so it looks smooth (image one, then image two shifted right one pixel, then image three shifted right two pixels, then image four shifted right three pixels and that takes us through a full byte of pixels) which complicated the animation loop since it ends with image one shifted one pixel to the right, which has to carry over to the next loop (image one shifted right one pixel, then image two shifted right two pixels, then image three shifted right three pixels, then image four not shifted but starting one byte over, etc).
That's not to mention that I had to draw the running man over the background image which requires merging the image data of the man with the background image. And to avoid really weird drawing artifacts, I used a double-buffer method (show one frame while drawing into a non-visible frame, then show the updated frame and use the previous frame to draw and repeat).
It was fun though. I don't think this will end up as a game any time soon, but it was nice to work on a computer that is so easily comprehensible by one person and where hitting the hardware is very easy to do (I think the last time I programmed to the hardware was in the mid-90s). I think my nostalgia has been sated for now.
Sunday, May 24, 2015
The crazy things that were done to make games run fast in the 8-bit era
The most amout of time spent in my simple graphics program is this loop:
clrloop ldd ,u++ ; load 2 bytes from background, increment pointer to next 2 bytes std ,x++ ; store them in current frame, increment pointer to next 2 bytes cmpu #end ; are we done yet? bne clrloop ; nope, keep going
Despite its name, it's not clearing memory. It's actually copying the background image to the current frame being drawn. I'm not showing the code before or after this as this post is really about this loop.
As written, each iteration of this loop takes 24 clock cycles (or just “cycles”) to run, meaning this code effectively copies one byte every 12 cycles. I recalled reading several years ago a crazy scheme to copy memory on the Motorola 6809 (the CPU used in the Color Computer) that involved using the stack register.
But before I get crazy, just how fast can I get the code to run?
Unrolling the loop a bit:
clrloop ldd ,u++ ; load 2 bytes from background std ,x++ ; store 2 bytes to current frame ldd ,u++ ; repeat this seven more times std ,x++ ldd ,u++ std ,x++ ldd ,u++ std ,x++ ldd ,u++ std ,x++ ldd ,u++ std ,x++ ldd ,u++ std ,x++ ldd ,u++ std ,x++ cmpu #end ; are we there yet? bne clrloop ; don't make me turn this CPU around!
and we get 8.5 cycles per byte.
Unrolling it more isn't worth it,
as the fastest we'll get is 8 cycles per byte
(assuming we unroll the entire loop to copy all 1,024 bytes;
but in doing so we'll use 4K in code (ldd ,u++
and std ,x++
are both two byte instructions) just to copy 1K in data).
Can we do better?
In checking the timings of various index operations, amazingly enough, adding an offset instead of just incrmenting the pointers is faster. This:
clrloop ldd ,u ; load 2 bytes from background std ,x ; store 2 bytes to current frame ldd 2,u ; load 2 more from background past the previous data std 2,x ; store them past the previous data ldd 4,u ; and keep this up std 4,x ldd 6,u std 6,x ldd 8,u std 8,x ldd 10,u std 10,x ldd 12,u std 12,x ldd 14,u std 14,x leau 16,u ; adjust pointers by 16 bytes leax 16,x ; as that's how much we copied cmpu #end ; are we there yet? bne clrloop ; enough!
gets us down to 6.5 cycles per byte! But unrolling this any further won't buy us a thing, as once the index passes 15, the instruction takes longer to execute because of additional instruction decoding. So this routine is pretty much it as far as a straightforward approach will take us. Not so bad though—almost twice as fast as the original 4 instruction loop. But to go even faster, we have to get crazy and bring in the stack pointer.
Why the stack pointer?
Because of four instructions:
PSHS
,
PSHU
,
PULS
PULU
.
The first instruction can save a number of registers onto the stack.
But looking at it another way: it's an instruction that can write up to 12 bytes into memory.
The second instruction is similar,
but instead of using the stack register,
it uses the U
register
(it's the “user stack pointer”).
The data written goes from higher addresses to lower addresses
(because traditionally,
stacks grow downward in memory).
The last two instructions to the reverse,
restoring a number of regsters from memory,
or,
reading up to 12 bytes into registers.
But we can't use all the possible registers these instruction support.
We can't use the program counter as that's rather important to executing the program
(it contains the address of the currently executing instruction—overwriting that will cause the program to start running who knows what).
We'll be using both stack registers so those are out.
We could use the CC
register,
but part of its use is to control the CPU—setting random values could be interesting.
Too interesting for me,
so that's out
(and it's only 8-bits—not like a great loss).
That still leaves us with four other registers we can use:
X
, Y
, D
(16-bit registers) and DP
(an 8-bit register).
So realistically,
we can transfer up to seven bytes at a time,
taking 12 cycles to read and 12 cycles to write,
for a theoretical maximum of 3.4 cycles per byte!
Woot!
The problem with this method is that the stack pointer is used by the CPU to keep track of where it is in the program.
Not only that,
but when the CPU receives an interrupt
(a signal that somehing has happened and needs to be handled now!)
it saves what it is doing on the stack and handles the interrupt.
And while on the 6809 the stack register can be used as a general purpose index register
(like we've been using the X
and U
registers)
we're hampered by the fact that interrupts happen.
In this case though, it can be done. The stack grows downward in memory—that is, as items are pushed onto the stack, the stack pointer is decremented lower and lower into memory. Taking this into account means we will be filling in the frame backwards, from the bottom of the frame towards the top. So we set the stack pointer to the bottom of the frame. If an interrupt happens, sure, there's some odd stuff written to the frame, but once the interrupt has been handled, the stack pointer is restored to were it was before the interrupt and we can continue copying the background, overwriting the garbage data added by the interrupt.
But pulling data off a stack goes from lower addresses to higher. And the bytes are pulled off in reverse order they were pushed (as expected—it's a stack after all—last in, first out). So the background data would need to be rearranged to take into account that we're reading the data from a low to high, storing the data high to low, every seven bytes are reversed, and that the memory in front of a frame can be expected to be trashed by an interrupt. Then there's the issue that 7 does not evenly divide 1,024—we'll have to handle the last two bytes as a special case.
But assuming the data is stored correctly and we have some memory in front of each frame that can be safely transhed, then the copying code would be:
clrloop pulu dp,d,y,x ; transfer seven bytes pshs x,y,d,dp cmpu #end-2 ; are we there yet? bne clrloop ; shut up! pulu d ; some post loop cleanup pshs d
and get 4.5 cycles per byte.
But this level of optimization should only be done if absolutely required. And in my case, it's not required (yet—if it ever will be). I'll be happy to stick with the 6.5 cycle version for now.
Monday, May 25, 2015
Oh that Florida!
Ironically, one of the things that may be contributing to Florida being shamed so often in the national media is something all Floridians should be proud of.
The terms "progressive" and "model for the rest of the nation" don't often appear in sentences with "Florida," but that's exactly how people view the state's open-records laws, AKA the Government in the Sunshine Act.
Since 1909, Florida has had a proud tradition that all government business is public business and therefore should be available to the public. That means all records, including photos and videos, produced by a public agency are easily accessible with a few narrow and obvious exceptions. Public officials are also required to open all of their meetings — even unofficial ones — to the public.
…
However, those same laws are also the reason your mugshot appears online days after your arrest, and those laws make it incredibly easy for journalists to write about weird Florida news stories.
You'll notice something when you read so many "Weird Florida" news stories. They almost always include the phrase "according to the arrest report."
As journalists, all we have to do in most cases is call the police department and ask for an arrest report, and the cops are required to give it to us. Nowadays a lot of cops simply email the reports, and some departments even post arrest records online. Some of the more dedicated weird-Florida-news reporters go through batches of arrest reports at a time.
You know, that explains a lot. It's not that Florida is crazier than the rest of the nation, it's just that the rest of the nation has decided not to air its dirty laundry.
Or in other words, Florida is the most transparent state when it comes to governance. Go figure.
Tuesday, May 26, 2015
Notes on an overheard conversation at The Ft. Lauderdale Office of The Corporation
“Man, the new hires seem to be getting younger and younger every day. And unruly.”
“You do realize today is ‘Bring Your Kid To Work Day,’ don't you?”
“…”
“Yup.”
“Is it too late to call in si—”
“Yes.”
“Okay.”
Notes on another overheard conversation at The Ft. Lauderdale Office of The Corporation
“It's too quiet in here. The kids are up to something.”
“Now, now, be nice.”
“I'm tellin you, they're planning something … ”
“All the kids have gone home.”
“Yeah, right! That's want they want us to think.”
Wednesday, May 27, 2015
Der Ring des Star Wars
So, by now you’re probably wondering what any of this has to do with Star Wars?
Well, as this essay will show, the six Star Wars films together form a highly structured ring composition. The scheme is so carefully worked out by Lucas, so intricately organized, that it unifies the films with a common universal structure (or what film scholar David Bordwell might call a “new formal strategy”), creating a sense of overall balance and symmetry.
Via Sean Tevis on GoogleMyTwitterFaceSpaceBookPlus, star wars ring theory | Mike Klimo
It's long, but it's an interesting new theory about Star Wars. Sure, we've all heard about George Lucas borrowing heavily from The Hero With A Thousand Faces, but a ring composition? That's certainly a new take on things.
But if the Star Wars films comprise a ring composition, it's only coincidental, as The Secret History of Star Wars made clear: George Lucas was making it up as he went along.
Thursday, May 28, 2015
Kung Fury
It's set in the 80s. It's set in Miami. It's a Kung Fu cop. It has Adolf Hitler (aka Kung Fürher). And it has a T-Rex. It's the ultimate in 80s actions films not made in the 80s. It's Kung Fury!
Oh lord is this thing over the top (so over the top it has its own music video staring David “The Hoff” Hasselhoff). It's more a series of quick scenes that ape common 80 action film tropes turned up to 11 than it is a film with a compelling story and character development. And all the more glorious because of it.
Friday, May 29, 2015
Does the removal of the audio from this video make it ironic?
This video previously contained a copyrighted audio track. Due to a claim by a copyright holder, the audio track has been muted.
Yeah, that happens on YouTube. But for some reason, the removal of the audio track on Anna's performance of “XXXX You” just makes it that much better, because she's “performing” it using sign langauge.
How appropriate.
Saturday, May 30, 2015
Magic is supposed to be … well, magical! Not scientific!
RPG magic systems can roughly be divided up into "fixed spell" and "freeform" mechanics. Fixed spell systems are often highly mechanistic, where the operation of each spell is exactly calculable. Freeform mechanics, on the other hand, call for the GM to judge the difficulty of a spell based on little information as well as a large degree of randomness.
Neither of these, however, is "mysterious". A mystery means that no pattern is obviously visible – but there is a hidden pattern. For a magic system to be mysterious, there must be hidden patterns which the magician character does not know at first, but which can with effort be discovered. In a game, this means that there must be either hidden variables or even hidden rules. An extreme of this would be that the GM secretly designs the magic system and only lets the player learn it a bit at a time (i.e. completely hidden rules). However, mystery can be injected by having hidden variables. i.e. How a PC's magic works depends on factors which are defined by GM, but which the player must deduce from other clues.
Via Hacker News, Breaking Out of Scientific Magic Systems
This is more observations about magic in role playing systems than it is a system to use to replace an existing magic system. The author is right that we (modern players) tend to be reductionist about magic systems because of modern science in today's world (I know I am a reductionist when it comes to magic systems as a player—I never did get a good grip on the magic system in Mage, probably the closest role playing system where “magic” is still mysterious and needs to be discovered because the system was so vague and contradictory) and maybe we need to loosen up a bit. I don't know … it sounds like it would be a lot of work for the GM, and possibly alienate the players.
Sunday, May 31, 2015
We wouldn't want anything to happen to the page rank on your nice website, now would we?
For these reasons, over the past few months we’ve been running tests taking into account whether sites use secure, encrypted connections as a signal in our search ranking algorithms. We've seen positive results, so we're starting to use HTTPS as a ranking signal. For now it's only a very lightweight signal — affecting fewer than 1% of global queries, and carrying less weight than other signals such as high-quality content — while we give webmasters time to switch to HTTPS. But over time, we may decide to strengthen it, because we’d like to encourage all website owners to switch from HTTP to HTTPS to keep everyone safe on the web.
Via Rob Landley's Blog Thing for 2015, Official Google Webmaster Central Blog: HTTPS as a ranking signal
And that was nine months ago. Is your website served over HTTPS?
This just appears to be yet more proof that Google is calling the shots on the web now.
Oh, by the way, your web server is HTTP/2 compliant, right? Wouldn't want anything bad to happen to your page rank, now would you?
Monday, June 01, 2015
Slow clap
- From
- Sean Conner <sean@conman.org>
- To
- XXXXXXXXXXXXXXXXXXXXX
- Subject
- We wouldn't want anything to happen to the page rank on your nice website, now would we?
- Date
- Mon, 1 Jun 2015 00:10:00 -0400
- Mime-Version
- 1.0
- Content-Type
- text/plain; charset=utf-8
- Content-Disposition
- inline
- Content-Transfer-Encoding
- quoted-printable
- User-Agent
- Mutt/1.4.1i
<blockquote cite=3D"http://googlewebmastercentral.blogspot.jp/2014/08/https-as-ranking=
-signal.html"
title=3D"Official Google Webmaster Central Blog: HTTPS as a ranking signal=
"><p>For these reasons, over the past few months we=E2=80=99ve been running =
tests taking into account whether sites use secure, encrypted connections a=
s a signal in our search ranking algorithms. We've seen positive results, s=
Oh,
thank you mutt
!
Thank you so very much for deciding now was the perfect time to content-encode the post I sent to mod_blog
.
I've been using you for what,
ten years now?
And not once have you ever decided on this behavior before?
But for whatever reason
[There are non-7-bit characters in the email body and SMTP is not defined as being 8-bit clean so of cou—]
[SHUT UP, Editor! I'm on a rant here! —Sean]
[Okay. —Editor]
mutt
decided now was the time to encode the email,
breaking mod_blog
in a way I've never seen before.
Way to go,
mutt
.
Way to go!
<slow clap>
Tuesday, June 02, 2015
Level 3 Diagnostics
Early in my career I worked on military flight data recorders, including the development of the software for the F-22's "black box". Those systems have SBIT, IBIT, PBIT and MBIT sub-systems were BIT is "built in test" and S = startup, I = initiated, P = periodic and M = maintenance. I remember making the Star Trek diagnostic joke myself when I was assigned the SBIT work.
Each BIT does varying level of testing based on it's runtime budget but there are a lot of very basic tests that don't make much sense until you see your first field report of some register bit "sticking". Its much better to ground a plane that can't add 1+1 than to find that out in mid- flight.
This comment (one out of many comments about testing critical software) really hit home, especially given the testing currently going on here in the Ft. Lauderdale Office of The Corporation (with the Monopolistic Phone Company, who's mantra seems to be “it's your fault we're not ready for testing!”). While I would love to order a Level 3 Diagnostic, alas, our software is not written with such diagnostics in mind (and given the difficulty we've seen from the other side it's clear their software isn't either).
In fact, I'm having a hard time even figuring out what a “Level 3 Diagnostic” would even mean in the compoent I wrote, much less every other component involved with “Project: Sippy- Cup.”
Reading up on SBIT, IBIT, PBIT and MBIT sub-systems, it seems that it's really only applied to avionics and possibly automotive computer systems. The closest thing to it is the POST that most PCs do when powered on, which seems to be the functional equivelent of SBIT. The rest, IBIT, PBITand MBIT, not so much.
Out of all the components in “Project: Sippy-Cup,” only mine has an explicit “health-check” function built in (which just basically says, “Yes, I'm running” and that's it) which is close to PBIT(from my understanding); everything else is queried for known data at fixed intervals. But diagnostics seem to be “search the logs and/or configuration for for anomalous behavior.”
Sigh.
Leverage the synergy between my company and Google's social media empire and search engine with a side of mocha
That was weird.
“Google Plus” (which is Google's attempt at Facebook) just called me on my cellphone.
Yeah. I didn't believe it was Google Plus either.
At first, it was a robot wanting to talk to the “business owner” of “a website” and to press one to talk with a “specialist” who could help “leverage the synergy between my company and Google's social media empire and search engine with a side of mocha” (or something to that effect, I wasn't really paying much attention frankly; I was just amused that “Google Plus” would even be calling me about “my domain”). Okay, I can play along.
I press “one.”
“Hello there! How can I help you?”
“You called me. I'm the ‘business owner.’”
“Okay! And your business is … ?”
“You tell me. Which business are you calling about?”
“So you are the business owner of the domain?”
“That is a possibility. I do own several domains. Which one are you calling about?”
“Well! Okay! Let me pull up the domains that are associated with your phone number. Um … you are in ‘Bokka Ratone?’”
“Yes.”
“33431?”
“Yes, that is the zip code around these parts. So what domain are you calling about?”
“Webboar.”
“Excuse me?”
“webboar. The domain “webboar.’ Double-you ee bee bee oh ay are.”
“No, I never had that domain.”
“Really?”
“For true.”
“Okay, what about flummux.org?”
“Yes, that's one of mine.”
“And domaincrawler.com.”
“Nope. I don't have anything to do with that one.”
“Oh, my mistake, that's probably how we found you.”
“Okay.”
“And who does your marketing?”
“I do.”
“Okay. Web site design?”
“Tha would be me.”
“Oh. So, are you intersted in leveraging the synergy between your company and Google Plus? We offer full search engine optimization and can help you market your site via social media.”
“No, I am not interested in that at this time.”
“Really?”
“Really.”
“Okay then.” <click>
Really? 50%?
- From
- Fredrick Tamata <ftamata@vanuatu.gov.vu>
- To
- undisclosed-recipients:;
- Subject
- RE:
- Date
- Wed, 3 Jun 2015 05:28:56 +1100
Hello,
Let's split fifty percent each from a lucrative deal I will like to discus with you, please respond if you want to know more.
"Trevor H"
It's not calling random people up claiming to be Google Plus and trying to get them to sign up for guarenteed search engine optimization, is it?
But in any case, no.
Wednesday, June 03, 2015
Isn't this how the Toxic Avenger got his start?
My manager is apparently under pressure by the HR Department of the Corporation Overlord Corporation to get the rest of his team to fill out the Employee Goals on the Employee Goal Website De L'année, and thus, I am now under pressure by my manager to appease the HR Department of the Corporation Overlord Corporation by filling out my “goals” on the Employee Goals on the Employee Goal Website De L'année. The first hurdle was to figure out which of a dozen different account IDs I needed to log into this site, and which of two dozen passwords to use.
Once that was sorted out, I started the process of filling out my “goals.” Fortunately, there was a pull down menu of predefined “goals” I could select from to save me the cognative overload of trying to come up with plausible sounding “goals” instead of the “goals” I really wanted to add, like “become a vegetarian skateboarding cab driver who saves the world” or “overthrow the illegitimate government of Patagonia” or something else equally silly.
So I'm running down this list of pre-canned results, like “keep accurate records” and “deliver on revenue” when I see, and I kid you not, “ensures 100% of hazardous waste is re-used/re-processed.”
…
SCORE!
How can I not use that?
Thursday, June 04, 2015
You can't make it look too easy
As I mention in the video, what’s really interesting is that this locksmith was penalized for getting better at his profession. He was tipped better when he was an apprentice and it took him longer to pick a lock, even though he would often break the lock! Now that it takes him only a moment, his customers complain that he is overcharging and they don’t tip him. What this reveals is that consumers don’t value goods and services solely by their utility, benefit from the service, but also a sense of fairness relating to how much effort was exerted.
Via Hacker News, Dan Ariely » Blog Archive Locksmiths «
Even Richard Feynman knew this trick back in the 40s:
I didn't need any tools, but I'd go to my office and look up the number of his safe. I had the last two numbers for everybody's safe in my office. I'd put a screwdriver in my back pocket to account for the tool I claimed I needed. I'd go back to the room and close the door. The attitude is that this business about how you open safes is not something that everybody should know because it makes everything very unsafe. So I'd close the door and then sit down and read a magazine or do something. I'd average about 20 minutes of doing nothing, and then I'd open it. Well, I really opened it right away to see that everything was all right, and then I'd sit there for 20 minutes to give myself a good reputation that it wasn't too easy, that there was no trick to it. And then I'd come out, sweating a bit, and say, “It's open. There you are."
Los Alamos From Below: Reminiscences 1943-1945, by Richard Feynman
You can't make it too easy else people will question the work required to make it look easy. I'm reminded of this joke: A large mainframe computer is broken, so the company sends for a computer repair technician. The technician comes in and sits down in front of the mainframe computer for a few moments, opens one of the cabinets, pulls a card out and replaces it, then says, “That will be $5,000.”
“Five thousand?” says the company owner. “You just came in, sat for a minute and replaced a card. How is that worth five thousand dollars?”
“Well,” said the technician, “It's $100 for the new card, and $4,900 for the time and effort for me to learn which card to replace.”
Friday, June 05, 2015
It's such a buggy day
“There's an FPL truck in the neighborhood.”
“Well, that explains why I couldn't log onto my home computer.”
Bunny and I were coming home from an errand to Lowes. Bunny was picking up supplies for a project and I wanted to test the Wi-Fi hotspot on my iPhone. The Wi-Fi hotspot worked wonderfully.
But logging into my home computer, not so much. I figured something was going on, perhaps the Monopolistic Phone Company's DSL going down again but no, it was FPL again.
Sigh.
Normally,
I type my entries into a text file which I mail to mod_blog
.
But to do that,
I need to send the entry to my email server.
And to do that,
I need to be logged into my now powerless computer.
But wait,
I thought,
I have a web inerface to mod_blog
,
I should use that!
Only,
the
last change I made
broke the web interface
(technobabble:
the editing template had a field for
Facebook
but I removed all support for Facebook;
there is some memory corruption somewhere in the code—I need to track that down.
Can you tell I use the web interface often?).mod_blog
couldn't find support for the Facebook portion of the template which caused
Just as my iPhone was running out of power.
Sigh.
Fortunately,
FPL restored power just then,
and I was able to remove the offending portion of the template,
and I'm now trying this yet again through the web interface
(on my iPad)
running through the iPhone hotspot just to make sure it works in an emergency.
I'm going to have to debug mod_blog
some more before I can use the web interface;
the EPS isn't quite up to snuff.
Dog food
Well, let's see if it works this time.
I was able to track the issue down to a double call to free()
.
But the really scary bit is that the behavior only exhibited itself on the webserver;
on my development box,
I never saw the bug.
Sigh.
Debugging on a production server—never a good thing.
But more on that after I finish dogfooding the web interface on an iPad over the iPhone hotspot.
Saturday, June 06, 2015
I'm lucky in that I run the server, so I can do this type of debugging
As I was unable to reproduce the issue on the development system, but it was all too easy to reproduce on server, I had no choice but to debug on the server. It's not an ideal situation but in this case, as I run the server in question and the appropriate software tools are installed, I figured I might as well debug on the server.
The approach I took is one I've been using for a long time—insert this bit of code:
volatile int g_debug = 1; while(g_debug) ;
into the proper code path (in this case,
the program was crashing in
cmd_cgi_post_show()
,
which is the function called when I want to preview a post from the web interface).
Then I can submit the data,
the web server will spawn mod_blog
,
and the infinite loop will give me a chance to attach the debugger to it
(setting up a fake web environment to debug
CGI programs is a pain).
And from there,
it was pretty straightforward to isolate the issue by setting breakpoints and examining memory.
The issue ended up being multiple calls to free()
,
and I suppose the difference in behavior between the development system and server can be attributed to the different versions of the standard C library.
Yes,
in an ideal world,
there would be no difference between the two,
but this isn't an ideal world and I have to make do with what I have.
Sunday, June 07, 2015
A note to Sweden: we don't have one-fifth cups over here
“I want you to read the directions,” said Bunny. She dropped a packet of Swedish meatball sauce she picked up at Ikea on my desk.
I flip the package over and start reading. “Pour one and a third cup of water—”
Bunny interrupted. “Read closer.”
“One and a fifth?”
“Yes. One and a fifth.”
“There's no such measurement.”
“Yes.”
“Wow.”
The meatballs from Sweden
Dinner turned out fine.
Swedish meatballs, lingonberries, and green beans.
Mmmmmmmmm.
Monday, June 08, 2015
TempleOS
TempleOS is somewhat of a legend in the operating system community. Its sole author, Terry A. Davis, has spent the past 12 years attempting to create a new operating from scratch. Terry explains that God has instructed him to construct a temple, a 640×480 covenant of perfection. Unfortunately Terry also suffers from schizophrenia, and has a tendency to appear on various programming forums with a burst of strange, paranoid, and often racist comments. He is frequently banned from most forums.
This combination of TempleOS’s amateurish approach and Terry’s unfortunate outbursts have resulted in TempleOS being often regarded as something to be mocked, ignored, or forgotten. Many people have done some or all of those things, and it’s understandable why.
…
Perhaps we should instead look at TempleOS as a research operating system: what can be accomplished if you’re not locked into established thinking, backwards compatibility, and market demands.
What can we learn if we are only willing to listen?
Via Hacker News, codersnotes / A Constructive Look At TempleOS
I've been meaning to link to TempleOS for some time now. It's not pretty. It's written in its own language (loosely based on C). And it's programmer is schizophrenic. Which is a shame, since the resulting software is impressive.
Sure, it might not be easy to use for a normal user, but as a programmer? All code (and everything is written in HolyC, with just a smattering of assembly) instantly crosslinked and documented. Images and sounds are directly embedded in the source code. There really is no distinction between the shell, the text editor and anything else, really.
The last time software was built like this was in research labs in the 60s and 70s. TempleOS is an impressive piece of work for one man. Everything was written from scratch. And there exist a ton of online video tutorials on how it works (that is, if you can watch them—I find it difficult to watch for more than a few minutes as Terry is not easy to listen to, and it's often hard to follow what, exactly, is going on since the operating system is so out there).
Tuesday, June 09, 2015
Notes on a barely overhead conversation at The Ft. Lauderdale Office of The Corporation
Rattle rattle rattle rattle rattle rattle rattle rattle!
“HEY! IS THERE SOMETHIGN GOING ON?”
Rattle rattle rattle rattle rattle rattle rattle rattle!
“I CAN'T UNDERSTAND YOU! THERE'S SOMETHING GOING ON!”
Rattle rattle rattle rattle rattle rattle rattle rattle!
“WHAT?”
Rattle rattle rattle rattle rattle rattle rattle rattle!
“DID YOU ASK SOMETHING?”
Rattle rattle rattle rattle rattle rattle rattle rattle!
“I DON'T KNOW! I ASKED YOU!”
Notes on an email about a barely overheard conversation at The Ft. Lauderdale Office of The Corporation
- From
- The Ft. Lauderdale Office Manager <XXXXXXXXXXXXXXXXXXXXXX>
- To
- The Ft. Lauderdale Office of The Corporation <XXXXXXXXXXXXXXXXXXXXXXXX>
- Subject
- Plumbing Work on 10th Floor
- Date
- Tue, 9 Jun 2015 15:30:13 -0500
Hello Everyone,
Please excuse the loud rattling noise occurring at this moment. There is a backup in the plumbing fixtures above us and what you are hearing is the snake.
They are unable to stop the job due to the issue at hand can get much worse. We have asked the plumbers to be as diligent as possible and complete the work as soon as possible.
The noise can be heard more towards the North end, so please move if necessary.
Sorry for the inconvenience,
The Ft. Lauderdale Office Manager
Rattle rattle rattle rattle rattle rattle rattle rattle!
“AH, SO THAT EXPLAINS THE NOISE!”
Rattle rattle rattle rattle rattle rattle rattle rattle!
“WE'LL BE TESTING IN VAN NUYS? I THOUGHT IT WAS SUPPOSED TO BE IN MURRAY HILL?”
Rattle rattle rattle rattle rattle rattle rattle rattle!
“YOU SHOULD GO HOME IF YOU FEEL ILL!”
Wednesday, June 10, 2015
Just a small observation about software projects
There are times when I'm sitting at work, answering questions (and it doesn't matter if it's face-to-face, over email, or via a chat program) when it feels like there is no one who fully understands how our product works. Not me, not the other developers, not my manager, no one!
It's not that nobody understands their part of the project—they do. But there are a lot of parts to the project. There's the front end code (multiple clients) which talks indirectly to the backend code (many moving parts) which is managed by the billing and provisioning code (many many pieces there as well), all written by different teams with sometimes less that perfect understanding of how the other parts work, and mangaged by two more teams (one for the servers, one for the network).
Not to mention the fun we have working with The Monopolistic Phone Company (“We don't have to care!”).
Sometimes, I find it amazing that what we do have works as well as it does—it could always be worse.
Thursday, June 11, 2015
What is Code?
A computer is a clock with benefits. They all work the same, doing second-grade math, one step at a time: Tick, take a number and put it in box one. Tick, take another number, put it in box two. Tick, operate (an operation might be addition or subtraction) on those two numbers and put the resulting number in box one. Tick, check if the result is zero, and if it is, go to some other box and follow a new set of instructions.
You, using a pen and paper, can do anything a computer can; you just can’t do those things billions of times per second. And those billions of tiny operations add up. They can cause a phone to boop, elevate an elevator, or redirect a missile. That raw speed makes it possible to pull off not one but multiple sleights of hand, card tricks on top of card tricks. Take a bunch of pulses of light reflected from an optical disc, apply some math to unsqueeze them, and copy the resulting pile of expanded impulses into some memory cells—then read from those cells to paint light on the screen. Millions of pulses, 60 times a second. That’s how you make the rubes believe they’re watching a movie.
Via Lobsters (but really, many, many, other sites linked to this), Paul Ford: What is Code? | Bloomberg
Wow.
I've been a fan of Paul Ford for many years (I even had a link to his site in the sidebar years ago but removed it as he hasn't updated his site in several years now) so it's always nice when I come across his work elsewhere.
This is a really good article on programming. It's also a really long article (38,000 words) on programming. And while it's ostensibly for the non- programmer (it uses second-person view point (which I do no like, Sam-I-am) to paint you as an executive in a company trying to fund some internal software development) I'm not sure if the average non-programmer won't be overwhelmed by the presentation, or be unable to follow along when it gets technical in spots.
Do I recommend it?
It's not technical enough for a programmer (and some of the details, while in spirit okay, are technically inaccurate) but I'm afraid it might be a bit too technical (or overwhelming) for its intended audience.
But yeah, I would recommend it.
You have been warned.
This is more “bootstrapping a langauge” than it is “creating a language”
Via Hacker News comes presentation on creating a language using only assembly language. It's an interesting project starting with the simplest thing that could work and building successive layers, gaining capabilities as you go.
But it's funny to see this being presented as novel, when that's how it was done back in the late 50s and early 60s. Personally, I might be inclined to go the Forth route instead of Lisp, but that's just me.
Friday, June 12, 2015
Overheard conversation at Chez Boca about the possible names for a feral lizard on the back porch
“You remember that lizard on the back porch?”
“The one you decided to keep as a pet?”
“Yes. I'm trying to come up with a name for him.”
“Godzilla.”
“That's actually my forth choice. My first choice is ‘Elliot.’”
“‘Elliot?’”
“From ‘Pete's Dragon.” Or ‘Smaug.’”
“What about ‘Eddie?’”
“Sigh. I hate your creativity.”
“So ‘Eddie” is it, then?”
“Yes.”
Saturday, June 13, 2015
The unbearable lightness of Forth
I mentioned
Forth
in conjunction with
bootstrapping a language
and I think it would be constructive to show just how small Forth can be.
I'm referencing JONESFORTH
,
an implemention of Forth bootstrapped from assembly language.
It took only 2,313 lines of assembly for JONESFORTH
(and easily half of that is comments describing the inner workings of the Forth environment)
versus the 3,663 lines of assembly for the first stage of amber
(the other language mentioned the other day).
Now,
granted,
the first stage of amber
is usable as is,
whereas JONESFORTH
takes another 1,788 lines of code in Forth
(and again, about half is just comments describing the implementation) to get a near fully fledged Forth system
(JONESFORTH
does not support DOES>
and why that is important will take another post).
So yes,
Forth is pretty easy to bootstrap.
(and small—the JONESFORTH
executable is only 17K—when
was the last time you saw a compiler that small?)
Sunday, June 14, 2015
An IDE for BASIC, on a machine with 128 bytes of RAM
- Your entire program can not exceed 64 symbols - a symbol being a number, variable, or reserved word (i.e. Goto, If, Then)
- There's a maximum of 9 lines, not really an issue considering the first item
- You only get integers from 0-99
- Only five math functions are available (+,-,*,÷,mod)
- In terms of graphics, you have two dots you can move by setting their coordinates
- You can play a range of beeps but I'm not musically inclined so I can't map them to notes
- Instead of a keyboard you have two 12 button pads to work with
If this sounds horribly limited and lame it's because you haven't yet thought about the hardware it's running on…
Via Reddit, HuguesJohnson.com - Atari 2600 BASIC Programming
Ah, the good old Atari 2600 Video Computer System. It could only address 4,096 bytes of ROM and 128 bytes (not megabytes, not kilobytes, but bytes) of RAM, and as far as graphics are concerned, the Atari 2600 is responsible for drawing every pixel on the screen, as the screen is being drawn by the eletronic beam on the television (or in other words, you are Racing the Beam).
It's not an easy machine to program.
So to even contemplate BASIC on the thing is insane. But it exists. And it has that oh so very sweet Atari cover art:
followed by the dismal reality that comprise most of the Atari 2600 programs:
Still, I find it a fascinating system. Like Hughs Johnson says, you could Tweet most Atari 2600 Basic programs they're so short. And because the language is so constrained, it seems like one could easily randomly generate scores of valid Atari 2600 Basic programs.
Hmmm … I have yet to figure out what my next Stupid Twitter Trick™ is to be …
Monday, June 15, 2015
Only in America
So, given that we have a white woman claiming to be black leading a NAACP chapter, comedians afraid to play to college audiences, a group dedicated to diversity excluding people based on skin color, and the Klu Klux Klan accepting black, Jewish and gay members (meanwhile, I appear to have 1992 on the phone ranting about wanting its election back or something), it's easy to think that satire has given up, gone home, and is curled in a fetal position under the covers in bed, wimpering for a simpler time.
But no, it's not given up—it's just that satire has gotten harder to detect: Black Chicago men start Klu Klux Klan chpater citing a declining culture as a reason. That is simply brilliant (but alas, real life still has a way of trumping satire when it wants to).
Tuesday, June 16, 2015
A constructive look at the Atari 2600 BASIC cartridge
I installed Stella (an Atari 2600 VCS emulator), downloaded the Atari 2600 BASIC cartridge and have been playing around with it for the past few days. If I'm going to do some Stupid Twitter Trick™ with it, I might as well know how it works, right?
And thus, this review.
Honestly, I don't think the Atari 2600 BASIC has ever had a fair review. It's pretty much reviled as a horrible program, a horrible programming environment and practically useless. But I think that's selling it short. Yes, it's bad (and I'll get to that in a bit), but in using it for the past few days, there are some impressive features on a system where the RAM can't hold a full Tweet and half the CPU time is spent Racing The Beam. I'll get the bad out of the way first.
Input comes from the Atari Keypads, dual 12-button keypads. If that weren't bad enough, I'm using my keyboard as an emulated pair of Atari Keypads, where I have to keep this image open at all times.
Okay, here's how this works. I want to enter this line:
A←A+1
(Ah yes! The “left arrow” for assignment. Mathematicians rejoice!) Upon startup, the Atari 2600 BASIC cursor is white. This is important, because this tells you what mode you are in. Hit a key when the cursor is white, and you do the functions labeled in white above each key. To get an “A,” you hit the bottom center button on the left controller (the one with the arrow circling around it) until the cursor turns blue, then you can hit the upper left key on the left controller (labeled “STATUS + A IF”). It's a bit hard to see, but yes, that “A” is indeed blue.
To get the “←” symbol (it's the top right button on the left controller) you hit the bottom middle button the the left controller until the cursor cycles back to red, then hit the upper right button on the left controller. Then cycle the cursor back to blue to get the “A,” then cycle to red to get the “plus” and the “1” (top left button on the right controller).
That's probably bad enough on the real thing. On the simulated Atarti 2600? Okay, what key on my keyboard is the “cycle” key? Then what key is the “A” key? Here's what I have to type to get that line of code:
xx1xxx3x1xxx19
But to be honest, it's on par with other keyboards of the time and may be a bit better, having actual tactile feedback instead of a simple membrane. I'm also picky about keyboards so I'm always going to bitch about the keyboard unless it's an IBM model M.
And given that the Atari 2600 only has 128 bytes of memory, it's expected that the programs are going to be rather short. I at first thought that you had 64 bytes for the program, but no—it's 64 bytes for the program, variables and runtime expression evaluation! That actually surprised me. Even worse, running this program over and over again (spaces added for clarity):
1 A ← 1 2 B ← 2 3 PRINT A,B
leaks memory!
No, really, that program, if run multiple times, will eventually exhaust all of memory. But not all programs leak memory. This program, if run over and over again (more on this little program in a bit):
1 D ← 1 2 HOR1 ← HOR1 + D 3 IF HOR1 = 0 THEN GOTO 5 4 IF HOR1 ← 99 THEN GOTO 2 5 D ← 99 - D + 1 6 GOTO 2
won't leak so much as a byte. Go figure.
Worse though,
is that each variabled used in the program
(and it doesn't matter if it's a predefined variable like HOR1
or a user defined variable like A
)
consumes three bytes out of the precious 64 bytes you get for your program!
On the plus side though,
unused variables (event the builtin ones) don't use space at all
(I figured this out by watching the RAM use in Stella).
The grahics are pretty pathetic as well.
There are two dots that can be manipulated.
The builtin variables HOR1
and VER1
control the horizontal and vertical position for one dot;
HOR2
and VER2
are used for the other dot.
The colors are fixed.
Oh,
and if the builtin variable HIT
is 1,
the two dots are in the same position.
The positions are themselves limited to 0 to 99, but that's because all variables are limited to the range 0 to 99. The values wrap though—add 1 to 99 and you get 0. Subtract 1 from 0 and you get 99.
Which leads us into the ugly.
Yes,
there are no negative values—everything is unsigned.
And the values are all limited from 0 to 99.
This stems from a unique feature of the Atari 2600 CPU,
the 6507
(a cheaper variation on the 6502).
That CPU can do math in either binary or binary-coded decimal
and the Atari 2600 BASIC uses the binary-coded decimal mode, which restricts the values from 0 to 99.
So while you don't have negative numbers,
you do in a way because of the way the math works.
99 plus 99 is 198,
but because the range is modulus 100,
the result is 98.
Add 99 again,
and you end up with 97.
I use this fact in the above program.
Line 5 negates D
—it converts 99 to 1,
or 1 back to 99.
Essentially,
1 to -1 and back again,
causing the dot to slowly crawl back and forth across the screen.
But now we finally arrive at what's good, or rather, what's amazing about this program.
First and foremost, it's an IDE.
Seriously.
Dispite it being only 4,096 bytes, there's a pretty credible, windowed(!) integrated development environment in there. If you look back at the keypad, you'll notice the first six buttons on the left controller are labeled:
- STATUS
- PROGRAM
- STACK
- VARIABLES
- OUTPUT
- GRAPHICS
Those are the various “windows” (and technically, they are windows, even if they don't overlap but are instead, stacked vertically on the screen) and the buttons there toggle the “windows” on and off.
The “STATUS” window (you can see it in the screen shot from the other day) shows memory usage (how many bytes, called “symbols”) and how fast the program will run (1, 2, 4, 8, 15, 30 and 60 are the speed values and they reflect how often the interpreter is run—once a second, twice a second, on up to 60 times a second). The “PROGRAM” window obviously contains the program (all nine lines if you have that many—and the IDE automatically numbers the lines for you even though it doesn't use them or store them—more on that below).
The “VARIABLES” window contains a list of the variables used in the program, listed as:
A is 1 HOR1 is 40 B is 2
“OUTPUT” is the text output window;
output of PRINT
. “GRAPHICS” is the laughable graphics screen.
Leaving the “STACK” window, which is a misnomer actually. It's not a true stack, since there is no concept of “subroutine” in the Atari 2600 BASIC. You could think of it as “TRON” as it actually shows you the execution of each statment that is abolutely amazing! Imagine each line below being shown one at a time and you'll get a feeling for how this works. We'll be following line 5 from the above program (assuming D is 1):
D D← D←99 D←99-D D←99-1 D←98 D←98+1 D←99
One more example, to show that the Atari 2600 BASIC also follows mathematical precedence. Here, A is 1, B is 2 and C is 3. The line of code we're following is:
D←A+B*C
and during execution:
D D← D←A D←1 D←1+B D←1+2 D←1+2*C D←1+2*3 D←1+6 D←7
Strange as it sounds, this blew me away. I don't think I've ever seen anything like this. Sure, in debuggers where you execute a line at a time. Or in assembly language, instruction by instruction. But never substeps in expression evaluation. And of course, you can always step through the code with the “STEP” button. I just find it amazing that all of this, as simple as it is, can fit in 4,096 bytes of code.
How it stores the code internally is interesting. Most BASICs I'm aware of store the line number as part of the program, but here, that's not done. Take this program for example:
1 A ← 1 2 HOR1 ← HOR1 + 1 3 A ← A + 5 4 GOTO 2
Internally in memory, it's stored:
Byte | Symbol |
---|---|
BC | A |
E8 | ← |
01 | 1 |
F1 | <end of line> |
B2 | HOR1 |
E8 | ← |
B2 | HOR1 |
E3 | + |
01 | 1 |
F1 | <end of line> |
BC | A |
E8 | ← |
BC | A |
E3 | + |
05 | 5 |
F1 | <end of line> |
A6 | GOTO |
02 | 2 |
FF | <end of program> |
Not a line number in sight,
which means GOTO
statements do a linear scan of the program
(a typical design choice of BASIC systems on 8-bit computers at the time)
but the end of each line is marked.
Weird,
but whatever works I guess.
Variables are stored after the program, sequentially:
Byte | Symbol |
---|---|
B2 | HOR1 |
EE | is (see below) |
02 | current value |
BC | A |
EE | is |
15 | current value |
As best as I can tell,
the value EE
is used when displaying the variables on the “VARIABLES” window,
and probably means “is.” It's probably done that way to avoid a special case when displaying data—it can be treated the same when displaying the program.
I'm guessing there's not much space left what with the font data and code to support the IDE in addition to running a
(admittedly very simple) BASIC interpreter for special casing the variables.
As a “proof-of-concept” it's an amzing piece of work. As an actual product, yes, it sucks, mostly because of the limitations of the hardware. The ideas behind it are incredible though, and I think it's gotten short shrifted because of the limitations, which is sad. There is something to learn from here.
Update Wednesday, June 17th, 2015 at 1:56 AM
I almost forgot—the IF
statement is an expression!
You can do the following:
A ← IF B = 15 THEN 40 ELSE 99
and A
will be 40 if B
is 15,
otherwise A
will be 99.
There aren't many languages I've used that have allowed this.
Wednesday, June 17, 2015
It's never lupus nor a compiler bug
While testing “Project: Sippy-Cup,” one of the components I was using for testing asserted:
tpp.c:63: __pthread_tpp_change_priority: Assertion `new_prio == -1 || (new_prio >= __sched_fifo_min_prio && new_prio <= __sched_fifo_max_prio)' failed.
This is not good.
This wasn't our code that called assert()
,
but pthreads.
Sigh.
The hardest part of debugging this was getting it to happen consistently (yes, it's one of those bugs) to test out various hypotheses.
It wasn't neglecting to initialize a variable. It wasn't a compiler bug. It turned out to be a abuse of the mutex API, where one thread locks a mutex, and some other thread attempts to unlock the mutex.
Thursday, June 18, 2015
It's not even a Heisenbug
I don't think it's a case of one thread releasing a mutex locked by another thread.
Whatever the bug, I can reproduce it rather consistently and every crash has always been along the same call chain. The mechanism used to trigger the problematic call chain is a way to work around a deficiency in POSIX (which I'm sure the original author of said mechanism would say stands for “Piece of XXXX In eXecution”)—not that I blame the original author, Unix and threads don't really mix that well (but then in my opinion, if it wasn't in Unix Version 7, it's not supported well or has a horrible interface—threads, networking, removable storage, graphical user interfaces, all have … issues under Unix).
But as of now, I've yet to figure out the actual root cause of the assert:
tpp.c:63: __pthread_tpp_change_priority: Assertion `new_prio == -1 || (new_prio >= __sched_fifo_min_prio && new_prio <= __sched_fifo_max_prio)' failed.
Every source I've found on the web with that bug states it has to do with an uninitialized mutex attribute. The code isn't using mutex attributes, and even when I added code to use a mutex attribute (initialized!) it still asserts. Sigh.
And the even weirder thing is—I don't think the component that's crashing is even being used by what I'm testing! See, the component I'm testing, E, makes a service request to T. T requires that service X (the one that is crashing) to be running, but the requests from E shouldn't cause T to make a request to X. X just sits there and periodically, logs a bunch of stats that basically show it's not doing a whole lot of work.
I got nothing.
Friday, June 19, 2015
No product survives first contact with production
Many months ago, my manager S asked about a “health check service” for “Project: Sippy-Cup.” Something that operations could query to see if my component was still up and running. I rejected the idea of embedding a web server in the component as being complete overkill (and really, any embedded webserver would swamp the amount of code that actually does the useful work in my component, which just processes one SIP message.
So I did the simplest thing that could possibly work:
a simple UDP service. It accepts a packet with the string “STATUS”
and replies with “OKAY.”
It was only a few lines of code,
and with netcat
I figured it would be a simple matter for operations to do a health check.
It seems that UDP is too confusing for operations to deal with,
so I changed the underlying protocol to TCP.
It's a bit more complicated to support as I now have to listen and accept connections,
but then it should be even easier for operations to handle it with netcat
.
The protocol stills accept a string of “STATUS” and returns with “OKAY”.
And it's still apparently too much for operations to deal with. Operations actually asked if they could send a SIP message, and I was like, Wow! If it's easier for you guys to send a SIP message for a health check, more power to you! But my manager nixxed that idea and we stuck with the current TCP version, which he feels is the simplest thing that could work.
I'm not sure what operations is actually doing.
My manager mentioned that my component was failing the health check,
yet when check it was fine
(using netcat
of course).
Yet the logs were filled with errors (“recvfrom: Bad file number” and “poll: Invalid argument”),
probably from all the failed attempts by operations to do a health check.
I did ask operations what is sent and how often. What they're sending is right, but they're asking “Areyoustillup?Whyhaven'tyouansweredme?Areyoup?Areyouup?McFly!McFly!Answerme!” before my component has a chance to even answer. I think they're a bit too aggressive. They don't.
Sigh.
Saturday, June 20, 2015
A park dedicated to The Art of the Brick
When I showed Bunny a video on making Lego gummy candy a few weeks ago, she said that was all the excuse we needed to go visit Legoland!
And lo! We arrived! To the sound of the Lego Theme!
Unfortunately grim reality asserts itself in the outrageous parking fee and ticket prices (really, you'd think at those prices you would at least get a small Lego kit, but then again, Lego was getting $36/lb for raw Lego bricks—wait a minute … that isn't that bad a price actually—it's about 500 2×2 bricks … wait! Where was I?).
Yeah, the high price tends to dampen the entire experience, making what could be wonderful (and I'm sure for the kids, it is) into something that's just a tad underwhelming.
Although the Lego sculptures are wonderful.
The pirate-themed water skiing show at the park was unfortunately cut short due to threatening weather.
Sadly, this meant that the kid behind us who really got into the show did not get closure, leaving open the question if Brickbeard escaped justice along with his bounty.
The weather then stopped threatening and made the decision to rain heavily, cutting our stay at Legoland a bit short and drenching us on the way back to the car.
Overall, I'm glad we went. Even though there wasn't anything special about the rides >per se, they were all Lego themed or made to look like they were built out of Lego bricks. We didn't eat at any of the restaurants, so I can't comment about them. The stores all sold Lego or Lego themed items (obviously—and Bunny did get the silicone molds for the jelly candies) so there isn't much to say about them either (other than the scores and scores of Lego kits all beckoning to be bought).
I just wish the park didn't cost so much.
A tigerwood cutting board
We met with Jim and Cis for dinner, two of Bunny's friends who live in the area. Seeing how she hasn't seen them in some time, Bunny thought it might be nice to give them a small present. So over the week, she made another cutting board, this time from tigerwood.
While it is a hardwood, Bunny found it somewhat difficult to plane smooth as it was prone to tearout and gouges. But she got the results she wanted.
The perils of hotelling
Sigh.
Nothing like a hotel (not the Legoland hotel) right next to a bar with the karaoke cranked up to 11.
Closing time can't come soon enough.
Sunday, June 21, 2015
These look to be the easiest crystals to make
Oooh … shiny!
And sooo easy to make …
[No! You are not using any of my pans, mister! —Bunny] [Awww … you're no fun! —Sean]
Monday, June 22, 2015
Technology is like a lightsaber, useful for both good and bad
Yesterday, news broke that Google has been stealth downloading audio listeners onto every computer that runs Chrome, and transmits audio data back to Google. Effectively, this means that Google had taken itself the right to listen to every conversation in every room that runs Chrome somewhere, without any kind of consent from the people eavesdropped on. In official statements, Google shrugged off the practice with what amounts to “we can do that”.
Via Instapundit, Google Chrome Listening In To Your Room Shows The Importance Of Privacy Defense In Depth
It's not that Google is spying on you, it's that Android is sitting there, listening for you to say, “Okay, Google!” and then sending the audio data to Google (as the comments at Hacker News point out). The real concern is law enforcement abusing this feature.
Tuesday, June 23, 2015
It's a wonder we survived this long as a species
“Free range parenting” is all but illegal and childhood is a completely different experience these days.
...
Our children have been enveloped in this softly padded culture of fear, and it's creating a society of people who are fearful, out of shape, overly cautious, and painfully politically correct. They are incredibly incompetent when they go out on their own because they've never actually done anything on their own.
When my oldest daughter came home after her first semester away at college, she told me how grateful she was to be an independent person. She described the scene in the dorm. “I had to show a bunch of them how to do laundry and they didn't even know how to make a box of Kraft Macaroni and Cheese,” she said. Apparently they were in awe of her ability to cook actual food that did not originate in a pouch or box, her skills at changing a tire, her knack for making coffee using a French press instead of a coffee maker, and her ease at operating a washing machine and clothes dryer. She says that even though she thought I was being mean at the time I began making her do things for herself, she's now glad that she possesses those skills. Hers was also the room that had everything needed to solve everyday problems: basic tools, first aid supplies, OTC medicine, and home remedies.
Via Instapundit, The Last Rebels: 25 Things We Did As Kids That Would Get Someone Arrested Today | Zero Hedge
They can't even make a box of Kraft Macaroni and Cheese.
Sigh.
The free range kids are going to eat the other kids alive. Not that that's a bad thing.
Of the list of 25 things we used to do as kids, I've done most of them (not playing ``dangerous games'' like dodgeball---I was smart enough to avoid that as the other kids were out for blood) but really, nothing in that list is out of the ordinary.
I'm blaming the 24-hour news cycle for this.
Wednesday, June 24, 2015
Be very very quiet … I'm hunting bugs
I now know what the bug is, and I want to confirm it. But it knows I know and thus it is hiding, taunting me. And the second I stop paying attention—I awake to a dead program!
Update many, many hours later …
Gotcha! And yes, it's exactly what I thought—a race condition. But catching and verifying is one thing. Fixing it—that's another issue altogether.
Thursday, June 25, 2015
A history of character encodings
From Reddit comes Character Encodings For Modern Programmers, a facinating look into the history of character sets used by computers. Did you know that some form of electrical communications have existed for about 175 years? Or that time-division multiplexing (multiple messages sliced into segments, sharing a single wire) was done as early as 1873? That Thomas Edison tried his hand at time-division multiplexing in 1876? Or that the first serial communication system using bits was designed in 1882? I didn't.
And we haven't even gotten to character sets yet!
I don't know … I just find this stuff interesting.
Friday, June 26, 2015
There's no reason for C to have just a single stack
This patch adds the safe stack instrumentation pass to
LLVM
, which separates the program stack into a safe stack, which stores return addresses, register spills, and local variables that are statically verified to be accessed in a safe way, and the unsafe stack, which stores everything else. Such separation makes it much harder for an attacker to corrupt objects on the safe stack, including function pointers stored in spilled registers and return addresses. You can find more information about the safe stack, as well as other parts of or control-flow hijack protection technique in our OSDI paper on code-pointer integrity (http://dslab.epfl.ch/pubs/cpi.pdf) and our project website (http://levee.epfl.ch).
Via Hacker News, Protection against stack-based memory corruption errors using SafeStack ⋅ llvm-mirror/llvm@7ffec83
I'm really surprised this wasn't done sooner. There's nothing in the C
Standard that mandates how the call stack must be
implemented, but it seems that for the past forty years or so, the system
stack (the stack the CPU uses to
store return addresses for subroutine calls or state information when
handling interrupts) has been the default place to store the call stack,
which is the prime reason why buffer overflows are
so dangerous (because with a buffer overrun, the attacker can embed machine
code and cause the CPU to return
to the embedded machine code to do nefarious things). Sure, it
might appear that dedicating another CPU register to point to this secondary stack might be wasteful,
but most C compilers on modern systems already use a second CPU register to point to the primary
stack (to make it easier to generate stack frames when debugging or analyzing
a core
dump). Also, the system stack wouldn't have to be so big—even an 8K stack on a 64-bit machine would easily allow a call
depth (A
calls B
which calls C
which
calls D
is a call-depth of 4) of over 500 (technically, 1,024
but this would disallow other uses of the stack, such as temporarily saving
registers, or handling of interrupts) which should handle most programs (the
exception being badly written programs with unbounded recursion; sidenote to Google: good one,
you got me).
This patch, however, seems to still save the call stack in the system stack with the exeception of arrays or items whose address is taken, and it stores the pointer to the “unsafe stack” in a thread-specific variable. It turns out the performance loss isn't that bad as most routines don't have such problematic variables to begin with.
Saturday, June 27, 2015
“If you don't know how to handle an error, crash the program.”
I still haven't been able to recreate this bug in mod_blog
.
Or rather,
I haven't been able to get
mutt
to use
“quoted-printable” encoding I was so not expecting.
All my attempts failed,
and mutt
sent the emails encoded as
“8bit” encoded
(which isn't an encoding per se,
more of an “indication” of what to expect).
Sigh.
In the meantime, I added a bit of code to detect the issue and abort immediately so I won't have to scramble to manually fix the blog like I've done twice now.
Sunday, June 28, 2015
It's rather simple, but you would never know it
Rob Landley is right—terminal control is obsolete. Precious few have actual terminals, and those of us who still use command line interfaces are using software programs that emulate physical devices talking to other software programs that emulate physical devices. Furthermore, all those software programs emulating physical devices have pretty much converged on using ANSI terminal control codes, so much of the reason for termcap has gone away.
So now it should be a simple matter to look up ANSI terminal control codes to see what to send to scroll the screen to the left, right?
Yeah …
And lest you think that page on xterm
control codes is intentionally incomprehensible,
it's not.
Well,
it is incomprehensible,
and it may be intentional,
bit it's not alone.
They
are all
pretty abysmal.
And they're all pretty abysmal because the actual standard,
ECMA-48,
is pretty abysmal as standards go.
Here's a representative sample:
5.3 Elements of the C1 set
These control functions are represented
a) in a 7-bit code by 2-character escape sequences of the form ESC Fe, where ESC is represented by bit combination 01/11 and Fe is represented by a bit combination from 04/00 to 05/15;
b) in an 8-bit code by bit combinations from 08/00 to 09/15; however, when the announcer sequence ESC 02/00 04/06 according to Standard ECMA-35 is used, the control functions of the C1 set are represented by ESC Fe sequences as in a 7-bit code.
and here's a translation into more modern terminology:
5.3 Elements of the extended ASCII control set
These control functions are represented
a) in a 7-bit code by a 2-character escape sequence of the form <ESC> <Fe>, where <ESC> is ASCII character 0x1B and <Fe> is ASCII characters 0x40 ('@') through 0x5F ('_');
b) in an 8-bit code by byte values between 0x80 and 0x9F; however, when the sequence <ESC> ‘ ’ ‘F’ (0x1B 0x20 0x46) according to Standard ECMA-35 is used, the control functions of the C1 set are represented by <ESC> <Fe> sequences as in a 7-bit code.
Yes, the ECMA standards represent characters using a (to me) bizarre column-based format which are kind of hexadecimalesque (4/13 is column 4, row 13) without being actual hexadecimal (0x4D), which makes reading the standard a bit more difficult. It was only reading these old standards in conjunction with this page did is start making a bit of sense.
For instance,
on the
xterm
reference page,
there's the sequence “APC
Pt ST
” but it's never defined what APC
or ST
actually are,
but Pt is defined to be `printable text.”
It's only by reading the other documentation closely that you realize that the sequence will either be
0x9F
<printable text>0x9C
or
0x1B
‘_’ <printable text>0x1B
‘\’
Which is beside the point,
because xterm
will ignore such sequences anyway.
Sigh.
The sequences themselves are pretty simple; it's just the presentation that universally sucks (and all the presentations except the ECMA-48 one assume you have read and understand the ECMA-48 standard).
Monday, June 29, 2015
But is it music?
I'm thinking Bunny would let me melt bismuth in her pans before she would accept Melodyne (link via Instapundit) as a valid music making tool. It definitely looks more flexible than Auto-Tune (say, add a harmonizing vocal track only to words sung in B, for instance). The vocals that are “corrected” are still noticeable—it's just a different effect than the robotic reverberations of Auto-Tune. Don't get me wrong, it's still noticeable, but it isn't … um … as tinny? Robotic? Computerized? as Auto-Tune.
So … Tool? Crutch? Does it depend upon your viewpoint? As a non-musician, I find Melydyne to be an incredible tool to allow people who otherwise can't carry a tune to create music. But Bunny, having had musical training, might think differently (I can relate—I hate PHP yet it allows people who aren't programmers write programs, for better but usually worse).
Tuesday, June 30, 2015
Guess what? You'll get an extra second of sleep tonight! Woot!
Gaining and losing an hour is a yearly thing.
Gaining a day happens once every four years.
But gaining a second?
It actually happens about every 18 months (but not on any type of set schedule). Wall Street is freaking out about it. What about you? Will you be watching Bobby Cannavale screaming “Leap Second!”? Or will you just spend an extra second sleeping tonight?
Wednesday, July 01, 2015
Drive
Hello from overcast a slightly drizzly Brevard, North Carolina!
We left Chez Boca at the ungodly hour of 7 AM. I drove for a few hours to let Bunny get some more sleep (me? I stayed up, deciding to “go to bed” a bit later than usual). At Ft. Pierce, switched places so I could get more sleep. We also encountered two bus loads (touring, not school) of middle school kids terrorizing the local establishments and causing long lines.
And wouldn't you know, the middle school kids were from Boca Raton. What are the odds?
There went an hour.
We switched again at a gas station just off the Grover, South Carolina I-95 exit. Here, the issue wasn't a ton of school kids from Boca Raton terrorizing the place, but being the only working gas station associated with an international brand for probably fifty miles in any direction. So there was the wait.
Waiting …
Waiting …
Oh so waiting …
Oh! An empty gas pump! Score!
No, I do not have a preferred customer card. Press “No” and wait.
Wait.
Oh, now I can insert my plastic card o' money. Select “debit.”
Select “debit.”
Select “debit.”
Ah, now type my PIN.
Try to type my PIN.
Try to type my PIN.
Try to hit “cancel.”
Hit “cancel.”
Slam my body into the “cancel” button.
Okay, let me try this again, only this time, skip answering “No” to the preferred customer card. Now answer “credit” and try to enter the ZIP code.
Try to enter the ZIP code.
Try to enter the ZIP code.
Skip trying to hit the “cancel” button and go straight for the body slam.
Then try all those steps three more times, proving that I am, in fact, insane.
Walk inside the store and inform the clerk of the troubles I've seen.
The clerk walks out, I hand over my plastic card o' money and watch as the insanity spreads.
After realizing the insanity of the situation, the clerk has determined the pump must be broken and to try another pump.
It sounded insane, but switching to another pump worked.
And another hour just flew by.
The only other incident on the ride up to Brevard—we hit Columbia, South Carolina during rush hour.
There went another hour.
Twelve hours after we left Chez Boca, we arrived at destination. Just as the All-Knowing All-Seeing Google predicted.
The Sunset Motel
Bunny and I are staying at the Sunset Motel here in overcast and slightly damp Brevard (just an inch or two more of rain a year, and the area around Brevard could be classified as a rain forest). We're staying here for two reasons:
- It has this cool 50s retro-style and it looked like it would be a fun place to try out (it's been here for as long as I remember—in fact, it's next door to the town homes I lived in when I was last living here thirty-odd years ago);
- I procrastinated too long in registering at The Red House Inn and we couldn't stay there the full nine days we planned on staying here.
It's a nice place and even if it's relentlessly gay:
it doesn't bother either one of us. We're okay with this. It's fun!
I think we're staying in The Star Room, as it's decorated with pictures of 50s movie stars like Audrey Hepburn, Marylyn Monroe and Elvis “Hunka-hunka-hunka burnin' love!” Presley.
Yes, I think this will be a cool place to stay for a few days.
Extreme free wi-fi, Brevard edition
Bunny and I stop by Ingles to pick up a few items when I notice an odd offering for a supermarket:
I … I don't know what to make of this.
Thursday, July 02, 2015
Downtown
Bunny and I have usually visited Brevard late in the year, sometime between October and December (inclusive). It's typically quiet, lots of parking downtown and very few people milling about.
Summer?
Oh My God!
The one downside to staying at The Sunset Motel is having to park downtown (it's a bit outside walking distance to downtown). And that's bad this time of year as there is no parking available. Even last night when we ate at The Square Root (their Pecan-encrusted Brie is to die for) we had trouble finding a parking spot. Today? We ended up parking several blocks west of downtown. The sidewalks were mobbed. And there was fifteen minute wait at Rocky's Soda Shop.
But for a retro-50s soda fountain they are rather high-tech. A waiter took our name and cell phone number, entered it into an iPad application which then called us when our booth was ready. Who knew there's an app for that? [Rocky's Soda Shop. —Editor] [Shut up, you! —Sean]
And even the barber shop was crowded today when usually we're the only ones there.
It's odd to think of Brevard as “bustling.”
What next? Sushi at the sea food counter?
ORLANDO, Fla. - Publix announced on its Facebook page it has activated free Wi-Fi at all of its stores so customers can access the internet and their apps – including the Publix app – while they shop.
Via Jeff Cuscutis on FaceGoogleMyPlusSpaceBook, Publix offers free Wi-Fi at all stores
That was certainly fast.
I caption a photo taking Publix to task for failing to have Wi-Fi in their stores only to just now hear them announce Wi-Fi in all their stores.
Wow.
I guess that's a thing now.
Extreme music appreciation, Brevard edition
Brevard takes music seriously, what with The Brevard Music Center. So I guess it isn't all that surprising to see a large banner of Beethoven hanging from the side of a building.
Friday, July 03, 2015
Dining in at the drive-in
Bunny thought we should try the Cardinal Drive-In (sadly, no website), a traditional drive-in burger joint just a few blocks north of The Sunset Motel. We arrived to a nearly empty lot (amazing, but we did arrive significantly before noon so maybe that helped).
Now, you would think that being at a drive-in, we would be eating in the car, but that would be too cliché—instead we ate in the dining room.
But to enmesh you in the whole drive-in theme, each booth had a phone where you could place your orders. The clerk could barely hear us through the device though, and instead walked over to our booth to take our order.
The food was quite good but I was rather surprised that in this day and age, there still existed a business that refused to accept plastic money. How authentically traditional (not to mention archaic but I digress).
But other than that, eating in and ordering face-to-face, our experience at the Cardinal Drive-In was exactly like eating at a drive-in burger joint.
Extreme food trends, Brevard edition
So at the drive-in, I came across this menu item—“breaded fried mushrooms!”
This isn't a thing I'm again, not aware of, right?
Right?
Binion's Roadhouse
Given that Brevard has been rather crowded, Bunny thought it might be a good idea to try nearby Hendersonville for dinner. “A steak house,” she said. “Binion's Roadhouse sounds good.”
So Binion's Roadhouse it is. Some thirty minutes later we're driving through the parking lot of Binion's. The full parking lot of Binion's. The line snaking out the front door and across the parking lot of Binion's. “This place seems full,” said Bunny. “Why don't we try downtown Hendersonville?”
So downtown Hendersonville it is. A few minutes later we're driving though downtown Hendersonville and not a free parking space to be seen. Sure, there were a few empty parking spots, but there were people nearby hawking them for $5.00 a pop. It didn't help that a few streets were closed off for pedestrian use only. Man, what is it with North Carolina towns in the summer? Are they always this crowded? “You know,” Bunny said, “Binion's wasn't that bad a choice.”
So Binion's Roadhouse it is.
The wait wasn't that bad, actually. Maybe ten minutes. And the food was worth it (except for the fried pickles—they were a bit greasy and to me, tasted a bit like fried fish). But vegetarians and those with nut allergies are advised to avoid the place.
There is also no relation to Binion's, the Las Vegas casino, excpept that the owner of Binion's Roadhouse is friends with the owner of Binion's and has a license to use the name (I asked).
Saturday, July 04, 2015
Moving from reservation to reservation
With our reservation up, Bunny and I bid our adieu to The Sunset Motel.
The only real complaint we had about the place was the plumbing—straight out of the 50s. The inflow of water during our showers did not match the outflow of water down the drain, so we were continuously up to our ankles in water. Also, there was a fine line (about 2mm) between “boiling alive” and “flash frozen.” And the less said about the toilet, the better.
The other complaint we had (and I'll admit this is totally a First-World 21st Century problem) was the rather lackluster wi-fi access point (more like a yo-yo wi-fi access point). Most of the time I used the “Personal Hotspot” function of my iPhone due to the poor performance of the wi-fi (and managed to burn through half our “Trust Us! One gigabyte is more than you need” data plan in a few days—damn you overly large webpages!—but I admit, I'm a special case here).
But with our reservation sunsetting on The Sunset Motel, there was a reservation rising at The Red House Inn.
Again, due to recurrent procrastination, I couldn't reserve the room we wanted, but that's not to say the room we got was bad. It's not.
And like the previous room, the bathroom has a shower with dual-shower heads.
Now I'm wondering if all the rooms here at The Red House Inn have dual-shower heads.
Also in the room is a beautiful writing desk that I've taken over.
And so far, the wi-fi access here has been fantastic (no First-World 21st Century problems here)!
Bada-BOOM!
To celebrate the Fourth of July, Brevard closes Main Street (Main Street! And a block north and south on Broad Street, the main road through town) to vehicular traffic for an all-day festival.
There were plenty of artists, food stalls, games and rides to keep the thousands that showed up busy. Even the rain didn't discourage anyone from slowly meandering about (the rain just made the meandering more frantic at first, then slowed it down a bit).
By the time of the fireworks show, 9:30 PM at Brevard College, Main Street had been opened, but a quarter mile segment of Broad Street, from the Transylvania Courthouse north towards the campus (the Courthouse is at the top of a hill) had been closed off to allow people a good view of the fireworks show.
Photo by Bunny
After the show, it was quieter in Brevard than our own neighborhood. I don't know if that's because of stricter enforcement of fireworks restrictions, or those setting off The Good Stuff™ just live further away from town.
I'm guessing the latter.
Extreme revolutionary acts, Brevard edition
At 3:00 PM, right in front of the Transylvania County Courthouse, a bunch of rabble rousers stood in the middle of the street and right then and there, started ranting about the government.
Stuff about intolerable taxes, a government that doesn't listen to its citizens, usurping the will of the Governors on a whim, giving foreign governments power over us, for waging unjust wars and other things that are outright trea—oh wait a second! Bunny just corrected me—they were reading The Declaration of Independence.
Oh.
How revolutionary!
Sunday, July 05, 2015
Extreme obviousness, Asheville edition
It was a quiet day today. Bunny and I drove to the Western North Carolina Farmer's Market in Asheville to pick up a few items and have lunch.
It was there I saw this:
No comment.
Monday, July 06, 2015
A prisoner of the bathroom
I have two complaints about The Red House Inn. One, the bed is too soft for my liking and I find it hard to sleep at times (Bunny's complaint about the bed—it's too high, requiring mountaineering equipment to literally climb into bed).
My second complaint has to do with the bathroom door.
The above picture is taken from inside the bathroom, and as you can see, there are no door knobs, just a pull handle on one side.
The pull handle is on the wrong side.
You see, there's a strip of wood running down the center of the door on the other side, covering the vertical gap between the two doors (although there's not much of a gap—in fact, the two doors are quite snug when closed). This strip of wood is attached to the door with the handle. When both doors are fully closed (and like I said, they're quite snug when fully closed) it is impossible to open the doors.
So last night, I'm pulling on the handle and the door is just sitting there, refusing to open because of that strip of wood running down the middle on the other side. There's nothing I can grab onto on the right side in the hopes of opening it up.
In the end, I had to knock hard on the door to get Bunny to open it.
Extreme cosplay potential, Brevard edition
For those of you looking to flesh out your Superman costume, look no further.
Okay, so it's lacking an actual payphone but when was the last time you saw an actual phone booth? Okay, when was the last time you saw an actual phone booth in person and not on television or in the movies?
Tuesday, July 07, 2015
Extreme road trip, Cashiers edition
“Let's take one of the roads out of town and look for a place for lunch,” Bunny said.
“Okay, sounds good,” I said.
Around 40 minutes later, we found ourselves in Cashiers, eating at The Carolina Smokehouse.
It's an excellent place, highly recommended if you are in the area.
Anyway, that's not the extreme road trip mentioned in the title. No, that goes to the previous owner of this license plate:
That's not a state license plate you see all too often here on the mainland.
Extreme lawn ornaments, Cashiers edition
While Brevard may go for cows as lawn ornaments, in Cashiers, it seems goat herds are the lawn ornament of choice.
Wednesday, July 08, 2015
A quaint little town
Ah, Canton!
What a picturesque town.
Bunny wanted to visit the Coast Lamp Mfg. Inc., a lamp factory known for their … well … lamps.
And Canton isn't that far, right? [42 miles per Google Maps. For Western North Carolina, that's considered “close.” —Editor]
And hey, the drive was nice.
Extreme street dancing, Brevard edition
During the summer, Brevard closes a block of Main Street to vehicular traffic every Tuesday between 6:00 pm and 9:00 pm so that people can dance in the street.
And here I thought choreographed dance numbers only happened in musicals.
Thursday, July 09, 2015
There and back again
Thirteen hours.
Rush hour traffic in Jacksonville.
Now home.
Zzzzzzzzzzzzzzzzzzz …
Friday, July 10, 2015
Receive valuable paper mail when you register a domain!
- From
- "DomainLLC" <admin@macropayday.com>
- To
- sean@conman.org
- Subject
- explodinggoat.com - Sean Conner - Boca Raton - 33431
- Date
- Thu, 09 Jul 2015 13:17:16 -0300
Hello Sean Conner,
I discovered your web site explodinggoat.com and I would personally like to invite you to examine our new program developed to assist those like yourself acquire additional earnings online.
Keep this top secret, this is building a MAJOR stur within the 'make money' online community…
We are not charging anything, just go to our website below and watch our video demonstration.
Regards, Richard
Unless you are the addressee (or authorized to receive for the addressee), you may not use, copy or disclose to anyone the message or any information contained in the message. If you have received the message in error, please advise the sender by replying to this email and delete the message.
Good thing I'm authorized to receive email for the addressee, otherwise I wouldn't be able to post this TOP SECRET information that is “building a MAJOR stur within the ‘make money’ online community.”
Please.
But I must say, the amount of snail mail I've received since registering a domain has been staggering. While on vacation, I received a 660 page catalog of office supplies from ULine among other junk mail, all presupposing I must be running a business because why else would I register a domain?
Well … it's their dime. Let them waste their money on me. Oh wait … did I just give them some page rank? D'oh!
“Space is big. Really big. You just won't believe how vastly, hugely, mind-bogglingly big it is. I mean, you may think it's a long way down the road to the chemist, but that's just peanuts to space.”
From Flutterby comes this video of traversing our Solar System at the speed of light. It's only (only!) 45 minutes long, and you want to know how far you get in just 45 minutes?
A bit past Jupiter (oddly enough, it also takes about 45 minutes to get a bit past Jupiter from Chez Boca—fancy that).
Saturday, July 11, 2015
Money, guns and Svalbard
The Sunday Gamers (you know who you are) might like this—it's actually very easy (if a bit pricy) to travel to Svalbard! (who knew?) And it's modern! Hotels with hot and cold running water and fast Internet connections.
Oh, and if you live there, you must carry a gun—it's the law.
Sunday, July 12, 2015
Build a pyramid by floating the blocks into position
Of all the … um … unorthodox theories of how the Egyptian pyramids were constructed, this theory of floating the blocks into position via water sounds quite plausible.
Monday, July 13, 2015
You feel the earth move under your feet
In fact, the science is robust, and one of the chief scientists behind it is Chris Goldfinger. Thanks to work done by him and his colleagues, we now know that the odds of the big Cascadia earthquake [approximately 8.3 —Editor] happening in the next fifty years are roughly one in three. The odds of the very big one [approximately 9.0 —Editor] are roughly one in ten. Even those numbers do not fully reflect the danger—or, more to the point, how unprepared the Pacific Northwest is to face it. The truly worrisome figures in this story are these: Thirty years ago, no one knew that the Cascadia subduction zone had ever produced a major earthquake. Forty-five years ago, no one even knew it existed.
Via Jason Kottke, The Earthquake That Will Devastate Seattle - The New Yorker
I knew about the San Adreas fault, and even the the New Madrid fault, but I did not know about the Cascadia subduction zone and as the article above points out, it has a history of “blowing” every 250–300 years, with the previous one being in 1700. And from reading, it doesn't sound good when the earth finally does move in the Pacific Northwest.
Monday! I should have known!
First day back on the job at The Corporation, and I am unable to log in and check my email. Hilarity ensues, and over the course of a few hours it gets worked out, and I find the following email:
- From
- The Corporate Overload Corporation <XXXXXXXXXXXX>
- To
- Sean Conner <XXXXXXXXXXXXXXXXXXX>
- Subject
- Your WIN2K Password is Expiring in 13 days
- Date
- Wed, 1 Jul 2015 10:20:03 -0500
Your password is expiring soon. If you’re in the office, you can set a new password by pressing
CTRL+ALT+DELETE
and selecting "Change a password…" If you’re working remotely you can change your password by logging into Outlook Web Access (XXXXXXXXXXXXXXXXXXXXXXXX) the selecting "Options" (on the top-right) -> "Change Password" (on the left menu).If you use ActiveSync on any mobile device, be sure to update your password there as well to prevent account lockouts.
Accounts that have expired passwords will be automatically disabled. If your account is disabled, you’ll need to contact XXXXXXXXXXXX (XXXXXXXXXXXX) for support.
Thank you,
Enterprise Services
Niiiiiiice! My password expired right when I started my vacation, and of course, I missed the entire two week nagging process to change my password …
But now, I can't log onto the VPN because the email password is somehow tied into the network password …
Tuesday, July 14, 2015
This is why it's so cheap to ship things halfway around the world
Perhaps it's because I have an interest in infrastructure, or because I found The Box (a book about shipping containers) a fascinating read (no, really!), or because I have an interest in automation, I found Dan Williams talk at the Cambridge Internet of Things really interesting (link via Tom Scott, which itself is an interesting video about the loading and unloading of a container ship in port). From a wholesale mall (only in lots of 100, please) in China the size of a city to showing just how automated a cargo ship really is (running Microsoft Windows no less—and yes, they have to reboot the computers from time to time), it's worth watching the presentation.
Okay, okay, I found it interesting. Your milage may vary.
Wednesday, July 15, 2015
When you expire on your vacation
- From
- The Corporate Overload Corporation <XXXXXXXXXXXX>
- To
- Conner, Sean <XXXXXXXXXXXXXXXX>
- Subject
- New SAS Work Order 4912, The account XXXXXXX for Conner, Sean has been disabled 07/15/2015 08:54:11
- Date
- Wed, 15 Jul 2015 11:57:13 -05:00
Dear Conner, Sean,
Thank you for emailing Systems Administration & Support. [When did I do this? Did I do this? Who did this? —Sean] Work order number 4912, has been created for The account SConner for Conner, Sean has been disabled 07/15/2015 08:54:11, on Wednesday, July 15, 2015 8:55:51 AM.
Please note that outside of core business hours for your region, workstation support is provided on an "Emergency On-Call" basis.
For on-call support issues pertaining to:
- Desktops & Laptop computers
- WIN2K account issues (lockouts)
- Desktop & laptop applications
Please call the North America SAS support line : (XXX) XXX-XXXX or xXXXXX
State the nature of your call, contact details and any other pertinent information and your call will be turned into an incident ticket and the On-Call technician will be paged.
For production support requests, please contact the Network Operations Center for your region - for issues pertaining to:
- Network issues
- Production issues
- External customer issues
North America INOC : XXX-XXX-XXXX or XXX-XXX-XXXX
Europe, Australia, other locations after hours:
European INOC: XX XX XXX XXXXXXX XXXXXX X
State the nature of your call, contact details and any other pertinent information and your call will be routed appropriately.
Kind Regards
Systems Administration & Support
XXXXXXXXXXXX
XXXXXX XXXXXXXX
You mean my long national nightmare of expiring accounts is not over yet?
Sigh.
Notes about an overhead voice mail message at The Ft. Lauderdale Office of the Corporation
- From
- Voicemail System <XXXXXXXXXXX>
- To
- Sean Conner <XXXXXXXXXXXXXXXXXXX>
- Subject
- New message 1 in mailbox XXXX
- Date
- Wed, 15 Jul 2015 11:57:43 -05:00
Sean Conner,
There is a new voicemail in mailbox XXXX:
- From
- "XXXXXXXXXXX XXX" <XXXXXXXXXX>
- Length
- 0:35 seconds
- Date
- Wednesday, July 15, 2015 at 11:57:47 AM
Dial *98 to access your voicemail by phone.
Visit http://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX to check your voicemail with a web browser.
There is?
Looks at phone.
Oh yes, there is. It probably has something to do with my expired account no doubt.
Picks up the phone,
and dials *98
.
“Ring.”
“Ring.”
“Ring.”
“Comedy Mail. Mailbox.”
“Comedy Mail. Mailbox.”
“Comedy Mail. Mailbox.”
What the— Okay, I think this is the password.
Dials a few numbers.
“Password.”
“Password incorrect.”
“Password.”
“Password incorrect.”
Oh! I guess it was this then …
Dials some different numbers.
“Password incorrect.”
“Password.”
“Password incorrect.”
<click>
Okay, let me try that again!
“Ring.”
“Ring.”
“Ring.”
“Comedy Mail”
Yeah, that's what I thought it said. Real funny.
“Mailbox.”
“Mailbox.”
Oh! It must be expecting my extension. Um … this is an “intelligent” desk phone talking to a custom business switch. Shouldn't it already know my extension? Bloody programmers!
Dials extension.
“Password.”
Dials some numbers.
“You have one new messages and no old messages. Please press …”
That's more like it.
Corporate password policies suck, but then again, you knew that already
Monday's expired account was The Corporation work email account. Today's expired account was The Corprate Overlord Corporation email account, which we only use to request vacation time.
The Corporation email account obstensibly expires after 90 days (but not really), while The Corporate Overload Corporation email account has a different expiration cycle of either 45 days or 50 days (but probably not really; Bob of Technical Support really didn't know). And it just so happened that both cycles converged on my vacation this year.
Sigh.
Also, while Bob of Technical Support could reset my password, I would be unable to change it for the next ten days!
Really?
I'm stuck with a temporary password for at least ten days?
Sigh.
Thursday, July 16, 2015
It's always nice when my code doesn't crash
I was reading this article (link via Hacker News) about fuzz testing a DNS server and when I saw that the problematic packets that caused the program to crash could be downloaded, I figured I would give them a try against my own DNS parsing code.
My code did not crash,
which is what I expected given that some of the tests I did included throwing random data.
But I might have to install afl-fuzz
and play around with it.
I'd really love to throw afl-fuzz
at the Protocol Stack From Hell™,
and while it would be cathartic,
in a way,
that's like shooting already dead fish in a wine barrel with a double barrel shot-gun at point-blank range.
Friday, July 17, 2015
I'm surprised we survived as long as we have
I blame the the 24-hour news cycle for this (link via Instapundit)—kids stuck inside all day because parents are afraid of shadows. I remember as a kid spending hours outdoors with my friend Duke wandering around the forest surrounding his home up in the Blue Ridge Mountains. The only thing we worried about was getting back in time to watch Batman and then getting back in time for dinner.
Heck, I walked home from school more times than I care to remember as a kid (and one time, I walked to school because I missed the school bus and didn't want to get into trouble). And when did it become Florida law mandating bicycle helmets for 15 or younger? I never wore a helmet. Nor knee pads, elbow pads, or gloves. Yes, attempting to skid the tires but having the bike shoot out from underneath and ending up with a bad case of road rash hurts, but it also teaches a valuable lesson—skidding a bike is stupid!
I also learned how to ride a bike in three days, but that was purely self defense on my part. My uncle would sit me on my bike, and shove hard. Losing my balance, I had two choices—turn into the closest large obstacle (telephone pole, corner mail box, a large rose bush) and crash headlong into it, or roll onto a four-lane road and crash headlong into traffic.
Fun times indeed.
But today?
As insane as some of the stupid things I did as a kid, parents today are just totally insane.
Saturday, July 18, 2015
Now if it were 10 ounces of To'ak chocolate …
I'd like to think this was staged (link via MyFaceGoogleBookPlusSpace). I can't comprehend the mind that would take a Hershey's chocolate bar over a 10 ounce bar of pure silver. I mean, Hershey's chocolate is okay, but it's not $150 worth of okay.
At least look at the silver before selecting the chocolate bar. Sheesh.
To'ak Chocolate
Per the previous post, if you are wondering if To'ak Chocolate is really worth more per ounce than silver, apparently it is.
Sunday, July 19, 2015
Tick tick tick …
Connoisseurs of disaster know that the official map of seismic hazards in the United States paints a fat red bull's-eye in the middle of the country, right where Missouri dovetails into Arkansas:
FEMA expects a major earthquake in the central United States to be the costliest natural disaster in American history, which as a California tech worker wounds my professional pride. We've spent decades building America's most valuable industry on top of a seismic powder keg, only to find ourselves outdone by a bunch of Midwestern cotton farmers. How could they erect a more precarious house of cards than Silicon Valley?
To find out, last spring I joined a group of Midwestern geologists and fellow-travelers on a sort-of-annual field trip to the New Madrid Seismic Zone. The goal of these trips, organized by Phyllis Steckel of Earthquake Insights, is to develop an eye for the kinds of structures and landscapes at greatest risk in a central US earthquake, to soak up the seismic ambiance of the place, to take killer ?before? pictures for when the Big One comes, and above all to put the fear of God into actuaries and insurance assessors, the only people who have enough economic leverage to make painful and expensive seismic retrofitting happen in the central United States.
Via Hacker News, Confrontin g New Madrid (Idle Words)
Just when you thought it was safe in the middle of the country, NOPE! There's a big old bulls eye right where Missouri, Arkansas, Illinois, Tennessee and Kentucky all meet, just waiting for the Big One to strike (probably just after the Cascadia subduction zone goes do doubt).
Monday, July 20, 2015
Tumbling through code, part II
The oldest bit of code in mod_blog
deals with what I call “tumblers.”
They're not true tumblers as defined by Ted Nelson,
but my implementation does allow a range to be specified.
It's a date range rather than an arbitrary set of characters though.
And the reason the code hasn't changed in fifteen years is because it was hard to write
the code,
given the features I wanted to support at the time.
Not only did I want the ability to specify a single entry,
like 2015/07/18.2
,
and a range of entries,
like 2015/07/01-09
but also have the ability to specify multiple,
non-sequential entries,
like 2000/08/11.1,2000/08/12.6,2000/08/13.4
while at the same time supporting the ability to specify ranges in reverse,
like 2015/07/09-01
,
all at the same time,
like 2000/08/10.2-15.5,2015/07/09-01,2003/07/04.2
.
So while I got the code to support a forward range and a reversed range,
in order to get the code out the door,
I dropped the non-sequential selection of entries.
The code just got too messy.
But over the past fifteen years,
a slew of issues popped up.
First and foremost was the issue of redundant links:
2015/7/4.1
and 2015/07/04.1
both refer to the same page.
This normally wouldn't be that big an issue except for Google,
which eventually would penalize a website with duplicate content under different links
(why do I even care about this?
Do I really care about my Google page rank?
Enough to let it rule my code?
Apparently I do.
Sigh).
Sure, I can tell that 2015/7/4.1
and 2015/07/04.1
are the same thing,
and you can probably tell the same thing,
but to a computer,
it can't.
Those are two distinct pages that just happen to have the same content.
So I had to hack in code to generate redirects to address this issue.
Now, 2015/7/4.1
would generate a redirect to the canonical version,
2015/07/04.1
. But there were still some corner cases I didn't cover,
such as 2015/07/04.01
,
which should redirect to 2015/07/04.1
,
or 2000/8/10.2-15.5
which should redirect to 2000/08/10.2-15.5
.
I finally had enough and decided over the weekend to fix the issue by rewriting the code. Yes, I know, you never rewrite code! But in this case, it's not the entire program but a portion (granted, it's about the only portion that hasn't been rewritten) and it's not like the code is entirely bug free (it's not). It mostly works but the code as written was just too convoluted to salvage (in my opinion). Besides, I felt that a more straightforward, “parse it a piece at a time” approach over the “be clever and as geneneral as you can be” approach would be better.
It was,
although it took several further revisions to work out all the corner cases,
such as the difference between 2015/04-2015/05
and 2015/04/05-05/06
(the first ending portion specifies a year and a month, whereas the second ending portion is a month and a day),
checking the dates for validity,
and
fixing the ranges when reversed
(it wasn't as straightforward as I thought it would be—can you tell I haven't used this option all that much?).
And not only did I manage to get 2000/8/10.2-15.5
to redirect properly,
but the reverse range 2000/8/15.5-10.2
as well
(check the links after clicking on them),
all the while reminding myself “don't be afraid of special cases.”
Tuesday, July 21, 2015
How Buildings Learn
Years ago I read How Buildings Learn: What Happens After They're Built on a recommendation, and I wasn't disappointed (oddly enough, it seems more programmers buy this book than architects). The book goes into depth on how buildings are adapted (or not—Frank Lloyd Wright's buildings are notorious for their inability to adapt, in addition to the leaky roofs) by successive tenants.
Now, the author of the book, Stewart Brand, has uploaded the documentary based on the book to Youtube (link via Jason Kottke). For a brief minute and a half peek at the type of content, there's The Oak Beams of New College, Oxford (one of my favorite bits from the book).
Wednesday, July 22, 2015
Going … going … gone
60% of my fav links from 10 yrs ago are 404. I wonder if Library of Congress expects 60% of their collection to go up in smoke every decade.
I've been afraid of searching all past links on my blog to see how many are dead or no longer point to the page I linked to. Several years ago I replaced the link on my very first post and I'm sad to say, the link on my second post is now dead (and the page it now leads to is nothing more than a missing image—sigh). Actually, it's quite painful going through the first month and seeing just how many links are now dead.
An interesting take on the Nigerian 419 scam
- From
- "Samuel Motsuenyane"<volunteer@cfur.ca>
- To
- undisclosed-recipients:;
- Subject
- ARE YOU DEAD OR ALIVE?
- Date
- Wed, 22 Jul 2015 20:11:18 +0100
Attention: Dear Customer,
We need to confirm that this is Truth Before the bank will Release Your Funds to one Jennifer Scott. This Office was contacted by one Jennifer Scott, From Canada Who Claim to be Your Partner she Promise to finalize everything regarding your Claim as Your Next Of Kin. she said that you were Involved In A car Accident Last year December 20014 and Die without providing a death certificate. We need to confirm that you are truly dead before we can Release the Fund to her.
We Believed That You are Dead But As a Public Office We need a Proof for Record Purposes Before We Can Release the Funds To her, Therefore, Your Silent is a Clear Proof That you Are Dead. Note we will commence On the Release of your Funds To your Next Of Kin from next week if we do not hear from you, May your Soul Rest in Perfect Peace Amen.
Regards
Mr. Samuel Motsuenyane
Director Debt reconciliation Department
First National Bank Os South Africa(FNB BANK)
Now this is an interesting take on the Nigerian 419 scam. I'm thinking that if I were to reply, I'd get email back saying that in order to receive the funds that would have otherwise gone to “Jennifer Scott,” I'll have to prove that I am alive. And then there will be some fee I have to pay to some bureaucratic department to get some form or other, and then some bribe or other fee, then some other fee and so on and so on.
Well played. A nice step up from the normal millions in some account in some random country from some random magistrate in some random country.
Thursday, July 23, 2015
The truth about the Lego movie
Even if I only saw this honest trailer of “The Lego Movie”
(link via Kirk Israel),
I still would have gone and seen the film movie.
Friday, July 24, 2015
The new way to version software
The Complete Drone-Ver Specification
This also lives at drone-ver.org.
Drone-Ver v.1.sleepy.0.0.calamitous.1437363538.7
Summary
Given a version number MAJOR.MOOD.ISSUES.SOCIAL.DICTIONARY.UNIXTIME .SEVEN, manage your releases as laid out in this comic:
- MAJOR is incremented when you feel like you've added something cool.
- MOOD is how you felt when you released this version.
- ISSUES is the number of open GitHub issues against your project.
- SOCIAL is the number of GitHub forks & favourites of your project.
- DICTIONARY is a random dictionary word.
- UNIXTIME is the unix time, and
- SEVEN is always the number seven (7).
Via Brian Yoder, Cube Drone - - Version Sacrifice
This is clearly a satirical response to Semantic Versioning as there are some who don't like
it. I found the Drone-Ver stuff hilarious (why yes, I am a geek—why do
you ask?) and according to it, mod_blog
should be at version
28.bemused.0.3.chinnier.1437723165.7
(assuming bug fixes are
“something cool”) instead of the current version of 4.7.5
.
But I also found Semantic Versioning to be a decent attempt to make version numbers have some semantic meaning. Semantic Versioning seems to be geared more towards libraries, and if there was one change I would make to it, it would be that minor versions (backward compatible changes or enhancements) shouldn't break user code (so that if you have a program that uses Foo major version 4.0.n, it should compile cleanly against 4.1.n, 4.2.n, etc. since they all should be compatible) but that bug fixes might break user code (if, for instance, you worked around it, or somehow used the bug as a feature of your code) but if you used the API as described, things should be okay.
Semantic Versioning breaks down for applications though, as there is no real API to speak of (which causes a change in the major version number). I think a good approach for applications with Semantic Versioning is that a major version should only change if configuration or data files change format (such that the new format is incompatible with the older format, or the older version can't load newer versions of the configuration or data files), new features or enhancements cause the minor version number to update, and bug fixes bump the patch version.
Using that criteria, mod_blog
would be at version
2.7.5
—there was a configuration file format change when I
switched from using my own half-baked configuration format to using Lua as the configuration
format (otherwise, the storage format for mod_blog
hasn't
changed one bit in fifteen years, although it has been enhanced, older
versions would be able to deal with the newer information by simply ignoring
it).
And just for the record:
date released | version | comment |
---|---|---|
Sat May 30 23:48:18 2009 -0400 | v2.0 | Yet another idea to add to the blogging engine |
Mon Jun 22 19:51:15 2009 -0400 | v3.0 | Removed more dead code. |
Wed Sep 9 03:22:07 2009 -0400 | v3.1 | Feature: Replaced how we pick the adtag |
Wed Sep 9 17:45:17 2009 -0400 | v3.2 | Feature: Some more template defs |
Sun Nov 6 02:01:41 2011 -0500 | v3.3 | Lua configuration |
Sun Nov 6 02:01:41 2011 -0500 | v3.4 | Document current bug in source code |
Mon Nov 14 22:51:10 2011 -0500 | v4.0 | Made sure the dependencies were correct in Makefile |
Tue Nov 6 14:37:10 2012 -0500 | v4.1 | Removed internal entry cache |
Mon Dec 31 22:46:01 2012 -0500 | v4.2 | The 'Gasp! Released at Last' Version |
Mon Mar 3 17:57:00 2014 -0500 | v4.3 | The 'Clean Memory' Version |
Fri Jun 27 03:02:24 2014 -0400 | v4.4 | The 'MyGoogleFaceSpacePlusBook Fix' Version |
Thu Aug 21 17:10:07 2014 -0400 | v4.5.0 | Display version of libraries used, in addition to the version of the program. |
Sun Apr 19 19:08:46 2015 -0400 | v4.5.1 | The 'Make the Makefile makier' Version |
Sun May 3 02:19:23 2015 -0400 | v4.6.0 | The 'XXXX FaceGoogleMyTwitterPlusSpaceBook' Version |
Fri Jun 5 21:53:54 2015 -0400 | v4.6.1 | Bug fix—double free |
Sun Jun 7 19:48:09 2015 -0400 | v4.6.2 | Bug fix—if not using email notification, code doesn't compile |
Sun Jun 7 20:03:00 2015 -0400 | v4.6.3 | Bug fix—don't use _IO_cookie_io_functions_t |
Sun Jun 7 21:51:40 2015 -0400 | v4.6.4 | Bug fix—potential double free (yet again). |
Sat Jun 27 18:09:27 2015 -0400 | v4.6.5 | Bug fix—encoded entries via email mess things up. |
Thu Jul 2 17:38:09 2015 -0400 | v4.6.6 | Bug fix—unauthorized person posting via email leads to double fclose() |
Mon Jul 6 17:53:30 2015 -0400 | v4.6.7 | Bug fix—a NULL tumbler crashes the program. |
Sun Jul 19 17:08:43 2015 -0400 | v4.7.0 | The 'Tumblers Reloaded' Version |
Sun Jul 19 22:28:18 2015 -0400 | v4.7.1 | Bug fix—date checking on exiting tumbler_new() was borked. |
Mon Jul 20 01:25:46 2015 -0400 | v4.7.2 | Bug fix—previous and last calculations were borked. |
Mon Jul 20 04:00:34 2015 -0400 | v4.7.3 | Bug fix—check tumbler date(s) against last entry, not the current time |
Mon Jul 20 17:52:24 2015 -0400 | v4.7.4 | Bug fix—current link was wrong |
Fri Jul 24 03:32:45 2015 -0400 | v4.7.5 | Bug fix—the assert() when comparing dates was wrong |
The history prior to version 2.0
is … um … murky. I had …
issues … with the previous version control system so pretty much the history from December 1999 through May 2009 have been lost in time, like
tears in rain. As you can see, the version numbers have been inconsistent
early on, but as time went on, I've done a bit better with the version
numbers (it's been more consistent with 4.6.0
onwards).
Saturday, July 25, 2015
Unintended consequences
I'm not here to make a moral judgement one way or the other, but I would like to point towards some unintended consequences. Point A:
How many babies prenatally diagnosed with Down syndrome (DS) are aborted in the United States each year? Well, we don’t know. …
A new study conducted by Gert de Graaf, Frank Buckley, and Brian Skotko and recently published in the American Journal of Medical Genetics [Read the full article for the full reference. — Editor] applies rigorous statistical modeling to diverse data sets in an attempt to provide the most accurate number possible. It is important to know over time what impact relatively new noninvasive prenatal screening (NIPS) technologies, only available since October 2011, will have on the already high termination rate after a prenatal diagnosis of DS.
…
The net result of their research is that abortion after prenatal diagnosis has reduced the population of individuals living with DS in the U.S. by approximately 30%. [Emphasis in original article and was not added here. —Editor] This should not be confused with the percentage of women who abort following a prenatal diagnosis. That number would certainly be higher. This reflects the overall reduction in the DS population, and takes into consideration total DS pregnancies, whether prenatally diagnosed or not. The authors state that prior to October 2011 and the availability of NIPS, about 72% of women elected to have traditional prenatal screens and only an estimated maximum of 2% went on to have invasive diagnostic procedures, i.e., amniocentesis or chorionic villus sampling. If prenatal screening becomes more widely available, as seems to be happening, then one would expect the number of terminations to increase.
Point B:
A genetic analysis of 409 pairs of gay brothers, including sets of twins, has provided the strongest evidence yet that gay people are born gay. The study clearly links sexual orientation in men with two regions of the human genome that have been implicated before, one on the X chromosome and one on chromosome 8.
Largest study of gay brothers homes in on 'gay genes' - New Scientist
The path (aka the “punchline”):
If people are born gay or transgender, Santorum posited, “it leads to a whole bunch of other situations,” like sex-selective abortions, for example.
“So if you can determine whether one of your children is gay, should we pass a law saying you can’t abort a child because you found out that child’s going to be gay? You can’t abort a child because you found out that child was going to be a woman? How would you feel about a law like that?” he asked Maddow.
Rick Santorum: I've met people who are no longer gay - Nick Gass - POLITICO
I won't claim I came up with this—that goes to Bruce Carroll (link via Instapundit). And I'm only bringing this up because some people are so blind to their own viewpoints they don't consider the ramifications of their myopic view.
Sunday, July 26, 2015
A plane flying 100 miles per hour and carrying 200 passengers and 5 crew crashes on the border of the United States and Canada. Where do they bury the survivors?
Frederick is perhaps best known for creating the “Cognitive Reflection Test,” a simple measure for whether a person solves a problem “quickly with little conscious deliberation” or through reflective, slow thinking. Kahneman includes the test in his book.
It has three questions:
1) A bat and a ball cost $1.10. The bat costs $1.00 more than the ball. How much does the ball cost? ____cents
2) If it takes five machines five minutes to make five widgets, how long would it take 100 machines to make 100 widgets? ____minutes
3) In a lake, there is a patch of lily pads. Every day, the patch doubles in size. If it takes 48 days for the patch to cover the entire lake, how long would it take for the patch to cover half of the lake? ____days
Via Hacker News, The power of slow thinking - Ideas - The Boston Globe
I will say, I got the first one wrong initially—Oh! It's simple! It's 10¢! But then I thought, Wait! This is a trick! Read that question slowly again … and I was able to puzzle it out. The second one I had to puzzle it out a few times to get it right, but because I program (I work with powers of two all the time) the last one was trivial.
When I tried asking Bunny about these, we had the following conversation:
“I was never good at these type of problems. You know, a train leaves Detroit going at 75 miles per hour, while at the same time, a train leaves Los Angeles going at 80 miles per hour. Where do they meet?”
“Yeah, that's easy.”
“Oh, really?”
“Yeah, they meet head-on.”
“Ha ha ha. Where?
“D'uh! In the United States.”
“Ahhhhhhhhrrrrrrrrrrrrrrrrrrrg!”
Monday, July 27, 2015
If a plane flies into Belgium, it must be Tuesday
I was reading an article about anomalous time zones (link via Hacker News) and when it mentioned an area around the International Date Line, I couldn't visualize how the International Date Line actually works.
In fact, I never really understood how it worked.
So I'm sitting there, reading about it and it doesn't make sense to me. Even when I picked up a globe and shone a flashlight on it (to simulate the sun) and spinning the globe, I still couldn't figure it out. I eventually found an animated visualization that worked.
Finally!
Tuesday, July 28, 2015
Notes on an overheard conversation in the Ft. Lauderdale Office of The Corporation to Bob of Technical Support
“Hello, Bob of Technical Support. How may I help you?”
“Yeah, I can't log into The Corporate Overlord Corporation web site and I think I need it reset.”
“Again?”
“Sigh. Yes. I didn't change the password after ten days and—”
“That should still work.”
“What?”
“Yes, that obviously weak and ill considered password we are forced to force upon you should still work.”
“But when … oh … ”
“Yes?”
“That's a one, not a lower-case ‘L’, and that's a dollar sign, not an uppercase ‘S.’ Stupid font … this is a clear case of PEBKAC. I'm sorry to bother you.”
“Okay then,
I shall log it as an ID10T
error then … ”
“Thank you.”
Wednesday, July 29, 2015
The pre-dawn airport traffic
At 5:00 this morning, I dropped Bunny off at the airport for her yearly visit to see her brother in Bremerton, Washington. I asked Bunny if she really needed to be at the airport so early, but she assured me that she would be fine. Besides, she had a 7:00 am flight and she needed to be there by 5:30 am anyway, so what was an extra half hour? I wasn't so sure the airport would even be open that early, but the joke was on me.
The airport was jammed with people.
At five in the morning!
Bunny even called later on, saying it took her twenty minutes just to get through the TSA checkpoint.
Sheesh.
Also, is it me, or does the Ft. Lauderdale-Hollywood International Airport logo look like a glazed donut?
Thursday, July 30, 2015
Yeah, let's breed more antibiotic resistant superbugs!
So suddenly these started showing up in the Ft. Lauderdale Office Of The Corporation:
It's bad enough with corporate password policies, but now hand sanitizer?
Sigh.
Worse, this is stealth hand sanitizer! Oh, that contraption may look empty, but noooooooooooooooo! Pass your hand underneath it, and you'll get automatic hand sanitizer dispenser ejaculate all over your hands. Ick.
I'm still asking: how did we ever survive without it?
Friday, July 31, 2015
Katelynn on Caitlyn
In August of 2008 on a rainy day in the Red Hook section of Brooklyn, I began filming the 21st season of MTV's The Real World. At 24 years old, I was the first openly transgender person in the show's then-16- year history. Only five weeks earlier, I had undergone sexual reassignment surgery.
…
So, while watching the first episode of Caitlyn Jenner's E! docuseries I Am Cait, I found myself in a unique position to understand and empathize with Ms. Jenner. I also noticed some things that were quite familiar.
Via Katelynn Cusanelli on MyTwitterFaceGoogleBookPlusSpace, 'I Am Cait' Through the Eyes of TV's First Trans Reality Star: Katelynn Cusanelli of MTV's 'Real World' | Advocate.com
Katelynn is probably the only person who's opinion on Caitlyn (and her show) you should take (you know … because they have the same first name). Also, I might be a bit biased, having met Katelynn several years before she became a reality television star.
I also wonder just how scripted Caitlyn's show will become (link via Instapundit).
Saturday, August 01, 2015
I've seen some bad C code in my time, but never anything like this!
Man, I'm glad I learned ANSI C instead of K&R C, if only to avoid egregious code like:
#define bitblt(s, r, d, p, c) (*((void(*)())0x430d6))(s, r, d, p, c)
Via Reddit, Rob Pike on Twitter
I shudder to think of the toolchain where casting an integer to a function address is easier than linking to the function.
Sunday, August 02, 2015
But at least South of the Border, South Carolina, is still south of the border
Dr. Frederick G. Berlinger built a house in what he thought was Polk County, N.C. The clarified [state] line puts most of the house in South Carolina. Some of it, apparently, was always there.
Via Hacker News, How the Carolinas Fixed Their Blurred Lines - NYTimes.com
I knew there were disputes over state boundaries throughout our history (such as the Walton War that took place in current day Tran sylvania County; and here's another article about it that contains a map of the area under question). But I didn't realize that there were still issues with state boundaries today.
Monday, August 03, 2015
Everything you wanted to know about making bassoon reeds but didn't want to ask
I did not expect a half-hour video on making a bassoon reed (link via Hacker News as a comment to an article about bassoon players being an endangered species). Nor did I expect a bassoon reed to be so finicky to make.
Tuesday, August 04, 2015
It's jury duty! What's the worst that can happen? I mean, besides being arrested?
Oh wonderful! In the snail mail box were five of the most dreaded words in these modern United States: JUROR SUMMONS—DO NOT DISCARD
Sigh.
I can only hope it goes better than the last time.
Oh my! Amazon dropping support for a legacy link!
For a moment there, I thought my post about jury duty finally broke the Amazon targeted advertising—all I was getting was a generic public service announcement about eating the hungry or something like that, with no link. Just bland text.
But no, all that happened is that Amazon stopped supporting a URL I've been using for the past nine years (which, to be frank, is odd behavior with Amazon; they're usually pretty good about supporting legacy links). It just took a bit longer than I expected to find the updated URL and now my self-targeted Amazon advertisements are working again.
Whew!
Update on Thursday, August 6th at 12:40 am
Wednesday, August 05, 2015
It's like a slow but very roomy airplane with good service
It's 2:00 pm and I'm here in the Hart Memorial Central Library in Kissimmee, Florida with some time to kill. Why I'm in the Hart Memorial Central Library is a story unto itself.
A week and a half ago, my friend Tom Lanahan, a train aficionado, invited me to ride along with him on the Georgia 300, a private rail car that is currently attached to end of the Silver Meteor and heading south. The only catch was that I needed to be in Kissimmee at 1:26 pm today in order to catch the train as it headed south.
I didn't miss the train—it's currently running two hours late, where as the north bound Silver Meteor, the train I took to Kissimmee, was on time, arriving in Kissimmee at 1:06 pm on the nose.
Thus, I have some time to kill.
This is the first time I've taken Amtrak and it wasn't a bad experience. The seats are wide, there's plenty of leg room (oh my God the leg room!) and the one-way ticket wasn't expensive at all (one way, since I'll be taking a private rail car back to Chez Boca). Lunch, while a bit on the expensive side (of course—they have a captive audience) was surprisingly good.
And I can't complain about the service. It's been excellent all along.
But there is one thing I can complain about …
The Write Train
Last year, Amtrak offered a residency program for writers, where Amtrak would provide a free round-trip ticket to qualifying writers. A type of “working vacation” if you will, where there is no distraction except for the clack-clack-clack of train wheels on rail as the train criss-crosses the continent. It sounds wonderful in theory.
I gave some thought to signing up, but I'm not a writer, nor an aspiring writer (even if I play one on the Intarwebs). I figured I would forgo the chance for a free train ride and let someone more deserving have a shot.
Yeah, like with 16,000 applicants I ever stood a chance of going.
Now we get to practice.
Calling the train ride “bumpy” is incorrect. It's not bumpy. It's not a constant “up-and-down” motion but more a “left-right” motion. I would call it “swishy.” It's a very swishy ride.
It's so swishy that it's damn near impossible to write! My typing rate was about a quarter normal and the use of the backspace key was at an all time high.
How in the world is anyone expected to write?
That is my biggest complaint about the trip so far. I had this intention of writing during the trip to Kissimmee but it proved a fruitless endeavour. It was just too damn swishy to write.
The other issue was the cell phone coverage. The Silver Meteor doesn't have wi-fi, but that's okay because I can use my cell phone as a hot spot. Or I would had the cell coverage been decent, and it wasn't.
What the XXXX, Verizon‽ I thought you were supposed to have like the best coverage of all celular carriers. Hello? Hello?
Hmm … I guess they can't hear me.
Anyway …
Three swishy hours later and all I have to show for it are nearly incoherent notes filled with typos. There is no way you can expect to actually write on a train trip.
Notes from a library in downtown Kissimmee
The guy sitting across the table from me at the library is falling asleep. His nose is about to hit the table, and he's snoring loudly.
The Georgia 300
Ah, the Georgia 300.
This is how you travel. From the Georgia 300 platform at the rear of the car:
to the dining room near the front:
and everything in between the two:
A person could certainly get spoiled traveling this way. How can you not like the custom China plates?
Or even the China cabinet?
On the down side, it's not cheap.
And four hours is not nearly enough time to enjoy the ride. Four days is more like it (and yes, I'm totally jealous of Tom).
Really Amtrak? Really? You using that slogan?
One thing I didn't mention on my train ride to Kissimmee was this:
This is apparently a thing.
Did no one at Amtrak know this is a famous line from a satirical movie about a distopic, totalitarian bureaucratic government attempting to fight terrorists and freelance heating engineers?
Sigh.
Still … it beats flying.
Thursday, August 06, 2015
Oh, now you tell me about it
- From
- Amazon Associates <XXXXXXXX@amazon.com>
- To
- Sean Conner <XXXXXXXXXXX@conman.org>
- Subject
- Associates Ad Unit Migration Notice
- Date
- Wed, 5 Aug 2015 21:13:47 +0000
Hello,
As previously communicated, we have been making changes to our technology platform that require you to replace some of the older product links, banners, and widgets currently hosted on your website.
Effective August 1, 2015, legacy product links were replaced with a public service announcement banner that will no longer send referring traffic to Amazon. You can now identify legacy product links, banners, and widgets that require updating by the presence of the public service announcement “Let’s Fight Hunger Together”. No further action is required if you have already made the requested changes.
Starting September 1, 2015, these legacy advertising units will no longer render, thereby either creating a broken link or the ad unit not appearing on your website.
Please use the following link to obtain more information and view the FAQs: https://affiliate-program.amazon.com/gp/associates/help/t401
Should you have additional questions, visit the following page to contact Customer Service: https://affiliate-program.amazon.com/gp/associates/contact
The Amazon Associates Team
Oh … you don't say … Why did you send this four days after the change?
Friday, August 07, 2015
Google, I think we need a little talk …
So I came across “What Colour are your bits?” for the nth time, and I thought I might link to it, but I want to make sure I haven't linked to it before. So I do what I usually do and try a Google search. Nothing comes up. But hold on—it's “colour,” not “color” so let me try that and even less comes up.
By now, I'm sure I have linked to that article before. A somewhat-quick-but-not-entirely-quick search locally on my server revealed that yes, I did link to that article.
Okay Google, what gives? You index everything pretty much instantaneously. I use you pretty much all the time to search my blog. And you can't find a single entry with an exact phrase? Are you just having a bad day?
And now I'm curious—what if I tried … oh … I don't know … BING?
Well, I didn't expect this—first result, exactly what I wanted to find. Well, Google?
Saturday, August 08, 2015
Alas, poor Yorick now has company
Bunny arrived home today and for a gift, she gave me Mort:
And now Yorick will have someone to keep him company.
Sunday, August 09, 2015
It does seem that no good deed goes unpunished
Growing up in rural Idaho, Gravity Payments CEO Dan Price remembers learning that one’s values are most sacred.
“My dad would ask me a question…He’d say, ‘How much money is your integrity worth?’ His point was there’s no amount of money that he would be willing to sell his integrity for. And that was ingrained in me at a very, very young age.”
Fast forward to today, the 30-year-old CEO is staying true to those principles. Just last week he announced he’d be taking a $930,000 pay cut to help afford raising the minimum wage at his Seattle-based credit card processing company to $70,000. This means that out of the 120 employees, 70 will be getting raises and 30 will see their incomes double.
Minimum Wage Increase: Gravity Payments CEO Dan Price Pays Every Employee $70,000
When I first heard about Dan Price raising all his employees' pay, I was like, more power to him! It's a private company and he can do what he wants. Personally, at the time, I felt it was great idea. And here is someone willing to put his money where his mouth was.
But like all ideas, there are unfortunately unintended consequences. And boy, were they big.
But even as Dan adjusted to life as a rebel hero and basked in his newfound popularity among third graders and single women, he quickly learned that whether he liked it or not, he had waded waist deep into the minimum wage debate and he would soon discover a few very hard lessons about the unintended consequences of hiking the pay floor.
First, some employees felt it wasn’t fair to indiscriminately give everyone a raise. That is, some felt Gravity should at least pay lip service to the notion that there's a connection between higher pay and performance and because the new pay plan didn't seem to acknowledge that link, the company lost some workers.
…
Next, Gravity began to lose some of its long-standing customers and while the across-the-board pay raise won the company more than enough new business to make up the difference, the new accounts won’t be immediately accretive and in the meantime, Gravity has had to hire more people to service the new accounts and thanks to the new salary floor, all of those new employees will eventually have to be paid $70,000.
…
Finally, Dan is now being sued by his older brother and as it turns out, Maisey McMaster had not included a "provision for legal fees in case my brother sues us" line item in the new budget, which means that ultimately, Gravity may have a hard time staying in business.
CEO Hikes Minimum Wage To $70K, Capitalist Tragicomedy Ensues | Zero Hedge
If there's one lesson to learn in all this, it's l'enfer est plein de bonnes volontés et désirs. If there's another lessons to learn, it's make sure you own the company before doing any harebrained schemes!
Monday, August 10, 2015
Oh by the way, they're rebooting King's Quest
I fondly remember playing King's Quest as a kid (and in fact, I think I still have the original game for my IBM PCjr). The hardest puzzle in the game that neither I nor my friend Bill Lefler could solve was the gnome's name (we ended up having to cheat and look at the answer to get past that puzzle). But the one thing this video of a playthrough (link via Shamus Young) does not show is the screen being drawn (a “feature” of the PCjr version), which is pretty neat the first thousand times you see it, but gets old afterwards. A side effect of that “feature,” though, is that any objects that could be manipulated (or were otherwise significant) would suddenly “pop” into existence once the screen was done drawing.
Ah, this video is more like it (when watching it, notice how the rock just “pops” into existence over the hole). There was also a mode (activated by a key combination—and it's been way too long for me to memeber what it was) that would cause the drawing to go even slower (I suppose it was for debugging purposes). Again, fun to watch for the first hundred times or so.
Tuesday, August 11, 2015
You have to make sure the vanilla is bone dry
About a week and a half ago, I used a vanilla bean when making some ice cream (yeah yeah, when the Bunny's away the carrots will play or something like that). I've seen on various television shows that you can dry the used vanilla bean and place it in sugar for a week or so to make vanilla sugar.
Hey, why not?
After I was done with the vanilla bean, I dried it off and shoved it into a contain of sugar in the spice cabinet. Only, I don't think I got it dry enough:
But the sugar smells wonderful.
Wednesday, August 12, 2015
A sign of the times
One challenge Gallego faces is translating metaphorical concepts from songs without compromising the whimsical nature of the lyrics. To navigate these intricacies, Gallego will often employ what she calls “indicating verbs:” she’ll mix two signs concurrently — one with her hands, and the other through her movement — to get an idea across.
For instance, in “Baby Got Back,” Sir Mix A Lot pontificates, “My anaconda don’t want none unless you got some buns.” When signing “anaconda,” Gallego combines the hand sign for “snake” with a sweeping motion that connotes she is referring to a penis. “I’m signing the snake, but visually, it looks like a big schlong,” she says, “and the audience gets it.”
Similarly, Gallego can’t just flash the sign for “butt” (literally, a simple finger point to the exterior); she has to symbolize that Sir Mix A Lot is referring to particularly voluptuous posteriors. Instead, she draws the shape — a gigantic, large-bootied silhouette — with her hands in the air. “You have to add action and movement to express his true lyric,” she says.
Gallego rarely signs the exact words a performer is saying. Instead, she’ll relate the concepts behind the lyrics. This is because literal interpretations more often than not confuse people (ie. for the phrase, “bear with me,” some interpreters flash the sign for the animal).
The Sign Language Interpreter of the Rappers
I would have never thought this was a real thing. I find it fascinating to watch (warning—you might not want to play this while at work due to language—but it's being signed, so you shouldn't really need the volume, should you? As an alternative, try watching a classic Michael Jackson song being signed).
Thursday, August 13, 2015
Notes on an overheard three-way conversation at a pseudo-Frenchesque bistro
A small restaurant in an unassuming strip mall along the road, devoid of any paying customers. Loud accordion music is playing over cheap speakers. The door opens …
“Ah, welcome to Prétentieux Bistro Français. You may zeet eenywhere you like! Perhaps monsieur et madame would like theez table, no?”
The table is small, small enough that it might make a single diner uncomfortable with anything other than a single hors-d'œuvre and a small glass of wine.
“That's a bit too small.”
“Le sigh. 'Ow about theez one?”
It's slightly larger. A single diner could eat here. Two, but only if they keep to the hors-d'œuvres.
“I like that one.”
“But of course! Ze best table! Pourquoi pas?”
“I have this coupon for the Faux Prétentieux Bistro Français—”
“That is nous.”
“You changed your name?”
“Our owner, he is, 'ow you zay, ‘capricieux?’”
“Whimsical.”
“Oui. Is that not what I zaid?”
“…”
“Eenyway, 'ere is ze dinnar menu. Theez is our zummer menu, you get an hors-d'œuvres, an entrée, and le dessert.”
The diners are each handed a cheaply laminated sheet of paper, listing a few appetizers, even less entrees, and a “you have to ask us if we have anything made today” dessert menu.
“Okay, I'll take the Soup Du Jour and a salad—”
“Non non non non non! Un hors-d'œuvres!”
“But the coupon I have is for a free salad … ”
“Theez is our zummer menu, you get un hors-d'œuvres, un entrée, and le dessert.”
“But I also want the free salad.”
“Theez is our zummer menu, you get un hors-d'œuvres, un entrée, and le dessert.”
“Salad!”
“Le sigh. Un instant … ”
The diners are left to ponder the summer menu for a few minutes.
“You can geet the zalad if you order from our other menu, 'ere. As you can zee, we have ze zame trois dinnar special, only more expenzive, as it is ala cart!”
“I see.”
“I come back een a few moments zo you can make your choice.”
“That was interesting.”
“You know, I think I'd rather eat at the Scottish place. Let's go …”
“Sounds good to me.”
Friday, August 14, 2015
Implementing a switch statement in Lua
From time to time,
the lack of a switch
statement in Lua comes up on the Lua mailing list.
Over the years I've been using Lua,
I only missed switch
when I first started,
as I was trying to write Lua like it was C.
But over time,
I've come to realize that a switch
statement isn't really needed that often,
not with first class functions.
A minimal implementation is just three lines of code:
function switch(key,case,otherwise) return (key[case] or otherwise or function() return nil end)(case,key) end
Which allows you to do something like:
switch(i, { [true] = function() print("i is true") end, [10] = function() print("i is is 10") end, ['foobar'] = function() print("i is 'foobar') end, [print] = function() prnit("i is the function print()") end, }, function() print("i is not something I recognize") end )
It's about the same syntactical overhead as the switch
statement in C or Java.
The reason I pass the case
table to each function is to allow a C-style “fallthrough” case,
like:
switch(i, { [1] = function() flag = true end, [2] = function(case) case[1]() print(flag) end, }, function() print "Unknown!" end )
Notice how when i
is 2,
we execute the case for then i
is 1,
and print flag
(also,
the indices are superfluous—I just included them to be explicit).
Also note how this can be used in an expression context—something that can not be said for C (or C++, or Java or … ).
Is this the best solution? Hard to say. It is the shortest, but it isn't that tolerant of of errors. But because it's so easy to implement, it can be adapted to just about any style you want.
Saturday, August 15, 2015
Snippits of an overheard conversation while driving to dinner
“Hmm … the on-ramps to I-95 are going to be closed.”
“They are?”
“Didn't you see the sign?”
“What sign?”
“You know, the big, 10′ electronic sign that flashes messages you see in construction zones?”
“Really? I didn't notice.”
“Sigh.”
“You know—”
“Yes, you aren't a trained observer.”
“Exactly.”
“Closed from 10 PM to 7 AM.”
“Doesn't affect me.”
“It could.”
“It's not 10 PM yet.”
“So you just ignore it.”
“Yup.”
“And when you want to get to I-95 and the on-ramps are closed?”
“Then I can't get onto I-95 from Yamato. Then I'll try driving to Congress and I-95, and find that on-ramp closed. So then I'll drive up to Linton, get stuck in horrible traffic because everybody that's trying to get on from Yamato or Congress are heading to Linton to get on. And because I'm stuck in horrible traffic, I'll be late to jury duty. And because I'm late to jury duty, I'll be arrested and slammed into jail. All because I have cable television.”
“Pbthpbthpbthpbthpbthpbthpbthpbth.”
Sunday, August 16, 2015
It's not quite impressive when you know you can buy it at Amazon
I came across Jamie Raven's first performance on Britain's Got Talent, and I must say, the animated card trick (really, I can't describe it—you should see it for yourself) was very impressive. But, this being on YouTube at a nice resolution, it's all too easy to go through the trick frame-by-frame and figure out how it's done.
Yes, Bunny and I went through the trick frame-by-frame, and by carefully (mild spoilers here) noting what we could and could not see, it became apparent how he did the trick.
But it gets even less impressive when you realize you can buy the trick on Amazon.
His previous trick in that video, that of turning several £50 notes into sketches of the judges, in front of them, by waving the bills back and forth, is still impressive but only by the fact that I don't know how he did it.
This seems to be a trend with his tricks on Britain's Got Talent. On his last appearance on that show, for his first trick, he pulls out a deck of cards, asks Simon Cowell to name a card, then fans out the deck face up, with the card that Simon Cowell named, face down. Assuming Simon isn't in on the trick, it's mindblowing (much like his turning £50 notes into drawings).
But I found his final trick (pulling a signed card out of a lemon) obvious (nothing in his hands, indeed!). It's a nice trick, but really (mild spoiler), he takes a few seconds too long doing what should be a quick move.
Monday, August 17, 2015
Why can't you backup, then download?
My iPad is low of charge, so I plug it into the Mac as I usually do in such situations. As soon as I do, iTunes pops up this message:
There are purchased items on the iPad “Sean Conner's iPad” that have not been transferred to your iTunes library. You should transfer these items to your iTunes library before updating this iPad. Are you sure you want to continue?
The “Cancel” button is highlighted, but I do have the option to hit the “Continue” button.
Sigh.
How hard could it be to do this?
There are purchased items on the iPad “Sean Conner's iPad” that have not been transferred to your iTunes library. This iPad will automatically be backed up before it is updated. Are you sure you want to continue?
Because that is most likely what I want to do.
Usually when this happens, I hit “Cancel,” then backup the iPad, unplug it, then plug it back in to get the new iPad software to download.
Or, short of that, why can't I backup the iPad while the new version of iOS downloads? I only have 36 minutes left (out of a 42-minute download) that that's plenty of time to backup the iPad. But noooooooooooooooo! It is incapable of doing this.
I thought Apple was better than this.
Update later today …
iTunes did a backup of the iPad anyway. What a poorly written warning.
Tuesday, August 18, 2015
We can link modules into a program with a linker, so where's the tool to link programs into a system?
I'm at work, and I'm looking at all the components that comprise “Project: Wolowizard” and how tedious it is to configure everything properly to work. Then I look at “Project: Sippy-Cup” and all the compoents and how tedious it is to configure everything properly to work. And then I had an odd thought.
Back when I was coding on an 8-bit computer with 16K of memory,
if my program got too big
(and I'm talking assembly language here)
I could break it up into individual files,
but I had to manage,
by hand,
all the memory addresses of each file and function.
For example,
one file might start assembling at address 4,096,
function FOO
might start at address 5,133,
and the end of that file might be at address 6,218.
That meant the next file had to start at address 6,219
(which meant making sure to tell the assembler that) and that I had to define the address of FOO
in the second file as being 5,133.
Later on,
when I had a computer running a real operating system
(well, it was MS-DOS,
which some claim isn't an operating system,
but a non-reentrant interrupt handler with delusions of being a real operating system but I digress)
I could take individual files,
compile (or assemble) them separately and not care what addresses were what,
leaving that up to another program to link everything together into a single program
(it's called a “linker”).
No longer did I have to worry about what address function FOO
would start—that was taken care of by other bits of software.
I could even include bits of output produced by other programmers
(called libraries—bits of precompiled code ready to be linked into a program)
automatically.
What I'm missing now is the linker for “Project: Wolowizard” or “Project: Sippy-Cup” as a whole. The piece of software that will take the various programs (each of which are comprised of multiple files compiled and then linked together into an executable) and “link” them up (in this case, configure all the components) for me automatically.
I'm wondering if it's even possible for such a tool in the general sense to exist.
Wednesday, August 19, 2015
Shaun the Sheep Movie
What a wonderful movie. Shaun the Sheep just wants a day off from the daily grind of farm life, but an accident sends the Farmer into the Big City and it's up to Shaun and the rest of the flock to rescue him while avoiding the Animal Control Officer. It's just a delightful film without one word of dialog (not that dialog is even needed in this movie).
The oddest trailer I've ever seen
Of course there were trailers,
and I saw the oddest trailer I've ever seen.
It was for an animated film movie
(because Bunny and I were waiting to watch an animated film movie)
so nothing odd there.
But it was in Spanish.
I've never seen a trailer for a foreign film movie that wasn't in English.
But it gets odder.
It was subtitled!
Okay,
yes,
it makes sense for a film movie in a foreign language to be subtitled.
But this wasn't a film movie—this was the trailer for a film movie.
And not just for a film movie,
but an animated film movie!
Granted,
I've seen subtitled animated films movies before but they weren't exactly aimed at mainstream American audiences but direct imports,
usually from Japan,
but I suppose some could exist from elsewhere in the world.
Odder still, the voice over, you know, the typical trailer voice over that typically begins “In a world about a land with time,” that type of voice over, was in English!
So Bunny and I saw a trailer for a sub-titled Spanish animated film movie with an English voice over.
About chickens and eggs.
I got nothing.
Thursday, August 20, 2015
“This is not the jury summons you are looking for.”
Beep boop beep boop beep boob beep beep boop boop.
Ring.
Ring.
“Welcome to the Palm Beach County Courthouse. If you are calling for jury duty, please press one—”
Beep.
“Please enter the nine digit juror number on your summons … now.”
Beep boop beep boop beep boop beep boop beep.
“You entered XXX XXXX XXX XXX XXXXX XXX XXX XXX XXX. If that was correct, press one—”
Beep.
“Please hold while I access your information … you are excused from juror duty and no further action is required from you at this time.”
They certainly picked the right actor to play a very young Darth Vader
Sorry for that “Phantom Menace clip in the previous post, but I did find something interesting when I was searching for it:
In today’s flashback to the ’90s news, former child star Jake Lloyd, the Turbo-Man fanatic from the Arnold Schwarzenegger Christmas movie Jingle All The Way and the infamous first Star Wars prequel The Phantom Menace, was arrested on charges including resisting arrest and failing to stop for a police officer in South Carolina this weekend. Police saw Lloyd speeding, and began to follow him, but rather than slow down, Lloyd sped up and according to TMZ eventually reached 117 miles per hour as he led police on a chase that ended with Lloyd crashing into a tree.
It's the picture that sells this—that yes, I can see that kid becoming Darth Vader.
Friday, August 21, 2015
I think there's a quote by Martin Niemöller that also might apply
Twenty years from now,
- You won’t necessarily know anything about the decisions that affect your rights, like whether you get a loan, a job, or if a car runs over you. Things will get decided by data-crunching computer algorithms and no human will really be able to understand why.
- The Internet will become a lot more like TV and a lot less like the global conversation we envisioned 20 years ago.
- Rather than being overturned, existing power structures will be reinforced and replicated, and this will be particularly true for security.
- Internet technology design increasingly facilitates rather than defeats censorship and control.
It doesn’t have to be this way. But to change course, we need to ask some hard questions and make some difficult decisions.
…
Here, too, the message was clear. You need our permission to operate in this world. If you step over the line we draw, if you automate, if you download too fast, if you type something weird in the URL bar on your browser, and we don’t like it, or we don’t like you, then we will get you.
In the future will we re-secure the Freedom to Tinker? That means Congress forgoing the tough-on-cybercrime hand waving it engages in every year — annual proposals, to make prison sentences more severe under the CFAA, as if any of the suspected perpetrators of the scores of major breaches of the past two or three years — China, North Korea, who knows who else — would be deterred by such a thing. These proposals just scare the good guys, they don’t stop the attackers.
We’d have to declare that users own and can modify the software we buy and download — despite software licenses and the Digital Millennium Copyright Act (DMCA).
This is going to be increasingly important. Over the next 20 years software will be embedded in everything, from refrigerators to cars to medical devices.
Without the Freedom to Tinker, the right to reverse engineer these products, we will be living in a world of opaque black boxes. We don’t know what they do, and you’ll be punished for peeking inside.
Via Lobsters, The End of the Internet Dream? — Backchannel — Medium
The general public just don't care about this stuff. And for some reason, this thought keeps going through my head: you can lead a horse to water, but you can't make it drink.
Saturday, August 22, 2015
How to fold your mind around imaginary math
The article How To Fold A Julia Fractal (link via Hacker News) isn't just about the Julia set and their relationship to the Mandelbrot set, but also an explanation of imaginary numbers. Even if you aren't that into math, the interactive visualizations of how imaginary numbers, Julia sets and Mandelbrot sets work is well worth checking out. This stuff almost makes sense now.
Sunday, August 23, 2015
This is not your grandfather's Theremin
Wow!
There's a Moog version of the Theremin. And it's being demonstrated by Kydia Kavina, the protégé of Léon Theremin, inventor of the Theremin.
Way cool!
Just as cool is Lydia Kavina playing the theme to Dr. Who on what looks to be a more traditional Theremin (along with some other very odd looking instruments).
Monday, August 24, 2015
There are no such things as bugs, only undocumented features
I found a very cool list of epic debugging stories (link via Hacker News). These stories are way more epic than my most epic bug, like the random memory corruption caused by a bad timing signal or the inability of email to be delivered past 500 miles (my personal favorite story).
Tuesday, August 25, 2015
A better way to implement system()
I am very surprised I haven't covered today's topic before, but try as I might, I don't think I have. Weird!
Anyway, twenty years ago when I was attending college, I designed and implemented my own programming language. Oh, it wasn't for a class (although I did use it for a class project—more on this below) nor for work (although I did use it for work at the time) but for my own curiosity (basically, how a typical Forth was implemented).
And perhaps the most unique aspect of my language came about because of a class project to implement a Unix shell.
There were two options—the first was to do simple command line parsing and environment variable substitution
(for example, where the environment variable $HOME
would be swapped out for its value) and file redirection as a solo project,
or do that,
plus some programming constructs like conditional statements or loops as a group project.
Well,
I already had the programming constructs in the form of my language so I had already done the majority of the group project.
All that was left was to parse and execute Unix commands.
It took all of two hours to add and it pretty much worked right the first time.
Now,
my language was based loosely on Forth but with an object oriented flavor.
The built-in types,
like integers,
strings,
floats,
were underneath objects and I managed to shoehorn in polymorphism so that
operators like “+” and “/” would work across types.
It was in this environment that I decided to make Unix commands first-class.
I think it was a brilliant design and it allowed me the ability to sling commands that one could not do from the command line
(even today).
The big one was redirection of stderr
.
Modern Unix shells will allow you to redirect stderr
to a file:
GenericUnixPrompt% make 2>/tmp/errors.txt
and you can, kind of, pipe it to another command:
GenericUnixPrompt% make 2>&1 | more
but that includes all the normal output as well.
There are times when I would like just stderr
piped to a command,
but there is no real way to do that.
But you could,
rather easily,
in my language.
Well,
“easily” being a relative term,
but still,
I could arbitrarily redirect stderr
to a complex pipeline of commands while at the same time redirect stdout
to another complex pipeline of commands,
where each of those commands could redirect stdout
and stderr
as well.
Twenty years later and it's this article (link via Hacker News) that got me thinking about my language (seeing how I'm the sole maintainer, sole developer and not even sole active user) and about the unique ability to treat Unix commands like any other value in the program. And I realized that I could probably do the same using Lua.
A few hours later and I have a near working “proof-of-concept” (in that it creates the proper structures but doesn't actually execute anything yet):
cmd = "logfile" + C("escanlog","--refer")^{} / (C('diff','-','expected')^{} / "escanlog-error" + "escanlog-out") + C("sort")^{} / "/dev/null" + C("uniq","-c")^{} + C("sort","-rn")^{} + "/tmp/output" cmd()
It would be hard to translate this into an actual command line,
seeing how you can't really pipe stderr
.
Breaking this all down,
the function C()
creates a Unix command object;
the first parameter is the program, all the rest become command line objects.
The “^” is normally the exponent operator,
but here,
I'm using it do define which environment variables I want set for the command
and here, it's an empty environment.
For example,
if I want todays date in Swedish,
I could do:
cmd = C("date","+%c")^{ LANG="se_NO" } cmd()
This is something you can do at the command line, but it gets unwieldy for a large number of environment variables or even a different environment variable per command. And since this environment blob is just a regular Lua table, you can set up a custom environment as a variable and reference it that way.
The sequence
cmd = "logfile" + C("grep","foobar")
will change stdin
to be the file logfile
.
But this:
cmd = C("ls","-l") + "list.txt"
will cause stdout
to be written to the file list.txt
.
So generally speaking,
“+” will redirect stdin
or stdout
,
depending upon where it appears
(in this case, “+” is non-commutative).
This will even work when redirecting stdout
to another command:
cmd = C("ls","-l") + C("tr","a-z","A-Z")
Redirecting stderr
is done by using “/” and it works similarly do “+”—if a string is specified,
treat that as a filename and redirect stderr
to that file,
otherwise redirect stderr
to a command
(where it becomes stdin
).
And it wouldn't be hard to extend this to support resource limits per command as well.
The odd choice of operators is due to the limited choice available for Lua 5.1—Lua 5.3 has more operators to choose from, but to be useful, I limited myself to what's available for Lua 5.1.
I'm actually surprised something like this hasn't been done before (or if it has, I'm not aware of it).
Wednesday, August 26, 2015
Debugging only gets harder with the passing of time
The story resurfaced this week in connection with the Germanwings crash. The standard causes of plane crashes, as Steve Coast explained, have been largely eliminated by the imposition of sensible rules or engineering fixes. Windows no longer crack at the corners. Doors no longer blow out. What remains are the oblique, non-obvious problems. ‘As we find more rules to fix more things we are encountering tail events. We fixed all the main reasons aircraft crash a long time ago… So, we are left with the less and less probable events.’ The world’s problems will, in short, get weirder. The seemingly sensible fixes we now add to the rule book will now increasingly run into unintended consequences: you can install impenetrable cockpit doors on the assumption that they will protect pilots from terrorists, only to find that they also prevent the captain (and passengers) from regaining the cockpit.
Why plane crashes are getting weirder – and if we’re lucky, other problems will too » The Spectator
I never thought of this, but it's obvious in hind-sight—all the easy problems have been fixed and what we're left with is weird interactions that lead to computer programs that occasionally crash only on Wednesdays.
Thursday, August 27, 2015
At the computers of craziness
I throw together things until it works then I move on. The real programmers will say "yeah it works but you're leaking memory everywhere. Perhaps we should fix that." I'll just restart apache every 10 requests.
I am not a fan of PHP for a variety of reasons, and it doesn't help that the author of PHP says the scariest things a programmer can say and people still use his stuff.
True story: back in 1997 or 1998, Smirk came up to me with two thick printouts and asked me for my opinion. The printouts were manuals for two different HTML processors, one called MetaHTML and the other one PHP. Even back then, I had an uneasy feeling about PHP and said we should go with MetaHTML (the website no longer exists and good luck trying to search for “MetaHTML”).
But little did I realize the eldritch horrors lurking
in the depths of R'lyeh PHP:
And if that's too simple, then just make the condition random:
class FooClass { } $foo = new FooClass(); $foo->bar = "qux"; $thing = "bar"; $qux = "th"; $grault = "ing"; $corge = "gnu"; echo $foo->${${$foo->bar}.${(rand(0, 9)<5)?grault:''}}, "\n";Yeah this will print
qux
half the time, and crash the other half. Want to add equality tests? knock yourself out:($foo->${${$foo->bar}.((${pouet}.${machin}===$pouet.${machin})?${machin}:${$pouet.$machin})});And that's where the second realization hits: you know how
foo
is just a string right? Then wouldn'tfoo()
be "a string with parens"?Well it happens that no:
function foo() { return "foo"; } echo "foo"(); $ php test.php Parse error: syntax error, unexpected '(', expecting ',' or ';' in test.php on line 4Unless you put the string in a variable itself:
function foo() { return "foo"; } $bar = "foo"; echo $bar();this will print
foo
. That's actually what PHP's owncreate_function
does. And yes, I can see the dread in your eyes already.Your fears are real.
Via Hacker News, masklinn comments on Today I learned about PHP variable variables; "variable variable takes the value of a variable and treats that as the name of a variable". Also, variable.
Run now! Look not at this page! Spare your sanity! Aiiieeeeeeeeeeeeeee eeeeeeeeeeeeeeeeeeee—
As long as the trucks aren't named Christine, we should be fine, right?
This past Sunday, Bunny and I were talking to my friend Tom Lanahan (the friend that invited me for a little train ride) about self-driving vehicles when I mentioned the tests that are underway in Nevada involving self-driving trucks. Tom was skeptical it would ever come to that, if only due to liability and felt that we were still years away from it happening.
Yeah …
The first autonomous vehicles to hit US highways will not be Google or Apple cars, but self-driving trucks – and they will be riding roads in Florida by the end of the year.
The self-driving construction vehicles, fitted with special rear-end crash barriers and lights, have been successfully demonstrated, driving using GPS waypoints and following a lead car, mimicking its path, braking and speed.
The specialised crash trucks are fitted with large signs to warn road users of the presence of workers and are used to protect construction crews resurfacing roads, painting lines, inspecting bridges or installing traffic signals.
Via Bob Anstett on FaceGoogleMyTwitterPlusSpaceBook, Self-driving ‘crash’ trucks to hit Florida highways this year | Technology | The Guardian
… it's a thing.
Friday, August 28, 2015
Reason #NaN I hate PHP
Quick, what does the following PHP code print out?
<?php for ($i = 'a' ; $i <= 'z' ; $i++) echo "$i\n";
Non-PHP programmers might say “the letters from ‘a’ to ‘z’ of course!” But sadly, no. It does not just print the letters from ‘a’ to ‘z’. Nope. It prints way more than you expect (link via Hacker News).
I realize that picking on PHP is like shooting dead fish in a barrel with a double barrel shotgun but I find it never gets too old.
Saturday, August 29, 2015
The Man From U.N.C.L.E.
Bunny's brother informed us that “The Man From U.N.C.L.E. was worth seeing and that was enough to convince her to go. Me? I've never seen the television show so I was going into this movie cold, having no idea what exactly to expect.
It was a very fun movie. I think the producers were smart in keeping it set to the 60s and not attempting to modernize the storyline at all. The cinematography was good, and the use of split-screen gave the film a unique look (and to me, gave it more of a “60” vibe). The use of flashbacks (in some cases, flashing back to a scene that happened less than a minute earlier) I felt was a bit excessive (like the audience can't figure out what might have happened) but overall, it was a solid, lighthearted action spy flick set in the 60s that didn't take itself too seriously, nor was it an outright parody like Austin Powers.
On the down side, about the only thing it had in common with the television series (according to Bunny—remember, I never saw it) were the names. In fact, the term U.N.C.L.E. doesn't even come up until the last line of the movie. But if there are sequels, I for one, wouldn't mind seeing them.
Sunday, August 30, 2015
Kernighan, Ritchie and Lovecraft, oh my!
C functions may be used recursively; that is, a function may call itself either directly or indirectly. Uninquiring souls may take this as just another peculiarity of those C folk, of whose ways their neighbours speak little to outsiders but much among themselves.
Keener news-followers, however, wondered at the events of the winter of 1927-28, the abnormally large number of calls placed upon the stack, the swiftness with which that list was sorted, the disturbing lack of heap allocation throughout the proceedings, and the secrecy surrounding the affair.
People in the nearby towns had talked about C for nearly a century, and nothing new could be wilder or more hideous than what they had whispered and hinted years before. Many things had taught them secrecy, and there was now no need to exert pressure on them.
Via Reddit, The C Programming Language: 4.10
Monday, August 31, 2015
The days when assembly was required
From about the mid-80s to the mid-90s, I pretty much programmed exclusively in assembly langauge. Along the way, I learned the 6809, (my favorite of the 8-bit CPUs), x86, 68000 (my favorite of the 32-bit CPUs), VAX and MIPS assembly languages, and I can recognize (and could probably program in if I had to) the 6502, 8080, Z80 and SPARC. I don't program much (if any) in assembly anymore. The CPUs have gotten too complex, the optimization rules too arcane and numerous and porting programs just gets tedious in assembly (they're practically a rewrite). Besides, compilers are getting better and better over time, negating the use of assembly except for absolute performance (when C or Fortran won't cut it).
But I still like assembly language, and I find these assembly gems (link via Hacker News) fun to read, even if they aren't that useful these days.
Tuesday, September 01, 2015
“Wasting my time? Okay, I'll waste your time.”
This is a fantastic idea! (link via spin the cat) If telemarketers can robocall us, we can certainly use a computer to keep them busy on the phone.
Oh, I would love to set this up.
Wednesday, September 02, 2015
I, for one, am still awaiting our self-aware robotic overlords
Roboticists at the Rensselaer Polytechnic Institute in New York have built a trio of robots that were put through the classic 'wise men puzzle' test of self-awareness - and one of them passed.
Via GoogleMyFacePlusSpaceBookTwitter, Uh-oh, a robot just passed the self-awareness test | TechRadar
I wouldn't worry too much—all this robot did was run some code to solve a logic problem, probably using code written in Prolog or something similar.
Nothing to see here … move along … the computer is your friend …
Thursday, September 03, 2015
The times were simpler back then
So I'm reading up on the history of chroot()
(link via Hacker News)
and it seems like at the time it was introduced,
chroot()
was rather simplistic in implementation and was nothing more than a way of specifying to Unix,
“when you see a leading ‘/’ replace it with this path.”
It seems security was an afterthought.
It also reminded me of this bit of Unix history, courtesy of The Bell System Technical Journal, Volume 57, Number 6, Part 2 (July–August 1978), which shows just how loose everything was in early versions of Unix:
The file system structure allows an arbitrary, directed graph of directories with regular files linked in at arbitrary places in this graph. In fact, very early
UNIX
systems used such a structure. Administration of such a structure become so chaotic that later systems were restricted to a directory tree.
Friday, September 04, 2015
Boatmurdered, or how I learned to stop worrying and flood the forests with lava
This morning I found the mangled body of a fellow dwarf in the hills outside of the capital, surrounded by elephant tracks. I didn't think he'd be complaining, so I emptied out his pockets.
I knew it was going to be a lucky day for me this morning, before the guards found me sleeping in the back of the warehouse and kicked me out. Not only was this guy loaded, but he had a piece of paper directing him to take charge of one of the colonies, some place named "Boatsmurdered". Whoever named that must have had a wierd sense of humor.
Well, I figured the place had never seen the guy's face, so I took the paper (and the money, of course) and started following the directions on the piece of paper.
I finally found the place. The directions lead me through a hidden passage that looked strangely like an escape tunnel. It wasn't till I got inside and tried to find out who was in charge that I found out why. It seems that this place is under siege by a combined force of goblins and Elephants, and the last ruler dug the tunnel to escape. It sounded like a good idea to me, but when I tried to open the door to the escape tunnel the whole thing collapsed. Guess I'm in for the duration.
Everything's in chaos here, no one can go outside because of the elephants and goblins. The dwarves kept acting like I should know what to do, so I told them to dig some fortifications we could shoot outside from. The other dwarves informed me, to my surprise, that the goblins had bows too. It was a frightening concept and made me long for the escape tunnel. But I had already noticed the other dwarves skeptical looks at me so I ordered them to do it anyway and said it would all work out.
Elephants. Mandrills. Goblins. Lava. Lots of lava. Burned forests. And all too common psychotic dwarves trying to carve a life out of a mountain of madness.
Welcome to Dwarf Fortress, a simulation game so rich with details, that it can simulate “a dwarven executioner, with broken arms unable to use his hammer, delivering punishments by biting his victims and tearing off their limbs, keeping one in his mouth for years.” Wow!
Boatmurdered is the story of a game of Dwarf Fortress, passed from player to player as they each had a chance of running a Dwarvish colony in the mountains.
It did not end well.
Saturday, September 05, 2015
Some impressions of DynASM
I'm curious to test something and, odd as it may seem, the best way to do this (in my opinion) was to try using DynASM, the dynamic assembler used by LuaJIT (of which it is a part, but can be used separately from, LuaJIT). The official document is lacking somewhat, so I've been following a tutorial (along with the tutorial source code) for my own little project.
I will not be re-covering that ground here (that, and the The Unofficial DynASM Documentation should be enough to get you through using it if you are interested in it) but I will give a brief overview and my impressions of it.
DynASM is used to generate code, specified as assembly, at runtime, not at compile time. As such, you give the code you want to compile in your program thusly:
if (token.type == TOKEN_NUMBER) | mov ax,token.value else if (token.type == TOKEN_VARIABLE) | mov ax,[g_vars + token.value]
All this code does is generate different code depending on if the given token is a number or a variable. The DynASM statements themselves start with a “|” (which can lead to issues if you aren't expecting it) and in this case, it's the actual assembly code we want (more assembly code can be specified, but it's limited to one assembly statement per line). Once we have written our program, the C code needs to be run through a preprocessor (the actual DynASM program itself—written in Lua) and it will generate the proper code to generate the proper machine code:
if (token.type == TOKEN_NUMBER) //| mov ax,token.value dasm_put(Dst, 3, token.value); #line 273 "calc.dasc" else if (token.type == TOKEN_VALUE) //| mov ax,[g_vars + token.value] dasm_put(Dst, 7, g_vars + token.value);
The DynASM state data,
in this case,
Dst
,
can be specified with other DynASM directives in the code.
It's rather configurable.
You then link against the proper runtime code
(there are versions for
x86,
ARM,
PowerPC or
MIPS)
and add some broiler-plate code
(this is just an example of such code)
and there you go.
It's an intriguing approach, and the ability to specify normal looking assembly code is a definite plus. That you have to supply different code for different CPUs is … annoying but understandable (you can get around some of this with judicious use of macros and defines but there's only so much you can hide when at one extreme, you have a CPU with only eight registers and strict memory ordering and at the other end, CPUs with 32 registers and not-so-strict memory ordering). The other thing that really bites is the use of the “|” to denote DynASM statements. Yes, it can be worked around, but why couldn't Mike Pall (author of LuaJIT) have picked a symbol not used by C for this, like “@” or “$”? Unfortunately, it is what it is.
Overall, it's rather fun to play with, and it was pretty easy to use, spotty documentation notwithstanding.
Of course it's slower, but I didn't expect it to be quite that bad
Time for another useless µbenchmark! This time, the overhead of trapping integer overflow!
So,
inspired by this post about trapping integer overflow,
I thought it might be interesting to see how bad the overhead is of using the
x86 instruction
INTO
to catch integer overflow.
To do this,
I'm using DynASM to generate code from an expression that uses INTO
after every operation.
There are other ways of doing this,
but the simplist way is to use INTO
.
I'm also using 16-bit operations,
as the numbers involved
(between -32,768 and 32,767) are reasonable (for a human) to deal with
(unlike the 32-bit range -2,147,483,648 to 2147483647 or the insane 64-bit range of -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807).
The one surprising result was that Linux treats the INTO
trap as a segfault!
Even requesting additional information (passing the SA_SIGINFO
flag with sigaction()
) doesn't tell you anything.
But that in itself tells you it's not a real segfault,
as a real segfault will report a memory mapping error.
Personally,
I would have expected a floating point fault,
even though it's not a floating point operation,
because on Linux,
integer division by 0 results in floating point fault
(and oddly enough,
a floating point division by 0 results in ∞ but no fault)!
But, aside from that, some results. I basically run the expression one million times and simply record how long it takes. The first is just setting a variable to a fixed value (and the “- 0” bit is there just to ensure an overflow check is included):
overflow | time | expression result |
---|---|---|
true | 0.009080000 | 1 |
false | 0.006820000 | 1 |
Okay, not terribly bad. But how about a longer expression? (and remember, the expresssion isn't optimized)
overflow | time | expression result |
---|---|---|
true | 0.079528000 | 46 |
false | 0.030125000 | 46 |
Yikes! (But this is also including the function call overhead). For the curious, the last example compiled down to:
xor eax,eax mov ax,1 add ax,1 into add ax,1 into add ax,1 into add ax,1 into add ax,1 into imul 100 into mov bx,13 cwd idiv bx into mov [$0804f50E],ax ret
The non-overflow version just had the INTO
instructions missing—otherwise it was the same code.
I think what's surprising the most here is that the INTO
instruction just checks the overflow flag and only if set does it cause a trap.
The timings I have
(and I'll admit,
the figures I have are old and for the 80486)
show that INTO
only has a three-cycle overhead if not taken.
I'm guessing things are worse with the newer multipipelined multiscalar multiprocessor monstrosities we use these days.
Next I'll have to try using the JO
instruction and see how well that fares.
When an issue requires a clone to resolve, I think the bus number is a bit too low
Over a month ago, Mike Pall announced he was leaving the LuaJIT project, which is sad, considering that LuaJIT has been pretty much his project. But he does have a sense of humor about leaving the project:
Suggested by http://www .freelists.org/post/luajit/Luajit-30-plan,2
Unclear how to find the upstream tracker to push this issue to. Will send pull request to upstream with DNA/RNA sequence, once this has been resolved.
Long-term enhancement request. No milestone assigned, yet.
Clone Mike Pall • Issue #45 • LuaJIT/LuaJIT
Sunday, September 06, 2015
I'm sorry, but I have to unfriend you—you're a credit risk
In short: You could be denied a loan simply because your friends have defaulted on theirs. It’s the kind of digital redlining that critics of “big data” collection have been warning of for years. It could make Facebook a lot of money, and it could make the Web even less safe for poor people. And it could be just the beginning.
Via Hacker News, Facebook Wants to Redline Your Friends List - Pacific Standard
This might warrant further investigation because it's just on the cusp of believability that this could be coming soon. And if it is true (and I'm not saying it is) I have to wonder what exactly the rationale is for denying a loan just because you have a few (or many) deadbeat friends. Because like follows like?
Monday, September 07, 2015
Some more usless µbenchmarks checking for integer overflow
Using the INTO
instruction to check for overflow was dog slow,
so what about using JO
?
Will that be slow?
The results speak for themselves (reminder—the expressions are compiled and run 1,000,000 times):
overflow | method | time | result |
---|---|---|---|
true | INTO | 0.009080000 | 1 |
true | JO | 0.006808000 | 1 |
false | - | 0.005938000 | 1 |
overflow | method | time | result |
---|---|---|---|
true | INTO | 0.079844000 | 46 |
true | JO | 0.030274000 | 46 |
false | - | 0.030245000 | 46 |
Even though the code using the JO
instruction is longer than either version:
xor eax,eax mov ax,0x1 add ax,1 jo error add ax,1 jo error add ax,1 jo error add ax,1 jo error add ax,1 jo error imul 100 jo error mov bx,13 cwd idiv bx jo error mov [$0804F58E],ax ret error: into ret
it performed about the same as the non-overflow checking version.
That's probably due to the branch prediction having very little overhead on performance.
One thing to notice,
however,
is that were a compiler to go down this path and check explicitely for overflow,
not only would the code be larger,
but overall it might be a bit slower than normal as there are commonly used optimizations
(at least on the x86 architecture)
that cannot be used.
For instance,
a cheap way to multiply a value by 5 is to skip the IMUL
instruction and instead do LEA EAX,[EAX*4 + EAX]
,
but the LEA
does not set the overflow flag.
Doing three INC EAX
in a row is smaller (and just as fast) as doing ADD EAX,3
,
but while the INC
instruction does set the overflow flag,
you have to check the flag after each INC
or you could miss an actual overflow,
which defeats the purpose of using INC
to generate smaller code.
And one more thing before I go,
and this is about DynASM—it's not stated anywhere,
but if you use local labels,
you have to call
dasm_setupglobal()
or else the program will crash.
I found this out the hard way.
Tuesday, September 08, 2015
“a cage for half a dosen of hennys or chekyn to have with yow in the galey, for ye schal have nede unto them meny tymes.”
“Guard your face carefully from the enormous insects,” instructs the guide for 12th-century pilgrims to Santiago de Compostela, “and if you do not watch your feet carefully, you will slip rapidly up to your knees in the quicksand.”
…
I hereby share some of this bounty with 21st-century travelers. Whatever the nature of your next voyage, this advice should help you get there and back again without falling victim to thieves, plagues or enormous insects. (You’ll have to find your own coping mechanisms for jet lag and selfie- stick malfunction.)
…
Seat location is also important. Wey offers this compelling advice: If you go in a galley, choose a seat in the top level, because the lowest level is “ryght smolderyng hote and stynkyng.” Similarly, Brasca cautioned that the traveler “should take care to arrange in good time — especially if given to suffering from the head on account of the movement of the sea — to have his lodging in the middle of the galley and near a middle door in order to have a little air.” …
Via Hacker News, What tips for traveling have changed since medieval times? Surprisingly few. - The Washington Post
Wow! To think that even 500 years ago they were complaining about conditions in coach!
I don't think anybody actually uses this instruction
Odd.
The runtime code for DynASM looks a bit … odd, and I was curious what Valgrind had to say about it.
[spc]lucy:~/source/jit>valgrind ./calc ==15664== Memcheck, a memory error detector. ==15664== Copyright (C) 2002-2005, and GNU GPL'd, by Julian Seward et al. ==15664== Using LibVEX rev 1575, a library for dynamic binary translation. ==15664== Copyright (C) 2004-2005, and GNU GPL'd, by OpenWorks LLP. ==15664== Using valgrind-3.1.1, a dynamic binary instrumentation framework. ==15664== Copyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al. ==15664== For more details, rerun with: -v ==15664== x = 1 - 0 vex x86->IR: unhandled instruction bytes: 0xCE 0x66 0xA3 0xCE ==15664== Your program just tried to execute an instruction that Valgrind ==15664== did not recognise. There are two possible reasons for this. ==15664== 1. Your program has a bug and erroneously jumped to a non-code ==15664== location. If you are running Memcheck and you just saw a ==15664== warning about a bad jump, it's probably your program's fault. ==15664== 2. The instruction is legitimate but Valgrind doesn't handle it, ==15664== i.e. it's Valgrind's fault. If you think this is the case or ==15664== you are not sure, please let us know. ==15664== Either way, Valgrind will now raise a SIGILL signal which will ==15664== probably kill your program. ==15664== Use of uninitialised value of size 4 ==15664== at 0xBC945C: _itoa_word (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBCCA09: vfprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBE5ACA: vsprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBD2DEA: sprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0x804ACA3: crashreport_hexdump (crashreport.c:154) ==15664== by 0x804B2BD: crashreport_handler (crashreport.c:388) ==15664== by 0xBB79AF: (within /lib/tls/libc-2.3.4.so) ==15664== by 0x804A9DD: main (calc.dasc:472) ==15664== ==15664== Conditional jump or move depends on uninitialised value(s) ==15664== at 0xBC9462: _itoa_word (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBCCA09: vfprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBE5ACA: vsprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBD2DEA: sprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0x804ACA3: crashreport_hexdump (crashreport.c:154) ==15664== by 0x804B2BD: crashreport_handler (crashreport.c:388) ==15664== by 0xBB79AF: (within /lib/tls/libc-2.3.4.so) ==15664== by 0x804A9DD: main (calc.dasc:472) ==15664== ==15664== Use of uninitialised value of size 4 ==15664== at 0xBC9474: _itoa_word (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBCCA09: vfprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBE5ACA: vsprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0xBD2DEA: sprintf (in /lib/tls/libc-2.3.4.so) ==15664== by 0x804ACA3: crashreport_hexdump (crashreport.c:154) ==15664== by 0x804B2BD: crashreport_handler (crashreport.c:388) ==15664== by 0xBB79AF: (within /lib/tls/libc-2.3.4.so) ==15664== by 0x804A9DD: main (calc.dasc:472) ==15664== ==15664== Use of uninitialised value of size 4 ==15664== at 0x804ACC0: crashreport_hexdump (crashreport.c:155) ==15664== by 0x804B2BD: crashreport_handler (crashreport.c:388) ==15664== by 0xBB79AF: (within /lib/tls/libc-2.3.4.so) ==15664== by 0x804A9DD: main (calc.dasc:472) not in syscall (0xB0044ADC - 0xB0044B31) valgrind: m_syswrap/syswrap-main.c:606 (vgPlain_client_syscall): Assertion 'sci->status.what == SsIdle' failed. ==15664== at 0xB000E029: report_and_quit (m_libcassert.c:122) ==15664== by 0xB000E1C2: vgPlain_assert_fail (m_libcassert.c:185) ==15664== by 0xB003AEA6: vgPlain_client_syscall (syswrap-main.c:606) ==15664== by 0xB002C826: handle_syscall (scheduler.c:623) ==15664== by 0xB002CAED: vgPlain_scheduler (scheduler.c:726) ==15664== by 0xB0014568: final_tidyup (m_main.c:2716) ==15664== by 0xB00141C9: shutdown_actions_NORETURN (m_main.c:2578) ==15664== by 0xB003C2D5: run_a_thread_NORETURN (syswrap-linux.c:139) sched status: running_tid=1 Thread 1: status = VgTs_Runnable ==15664== at 0xD080B5: pthread_once (in /lib/tls/libpthread-2.3.4.so) ==15664== by 0xC9BB76: free_mem (in /lib/tls/libc-2.3.4.so) ==15664== by 0xC9B811: __libc_freeres (in /lib/tls/libc-2.3.4.so) ==15664== by 0x4000336: _vgw_freeres (vg_preloaded.c:62) ==15664== by 0xBB78C4: raise (in /lib/tls/libc-2.3.4.so) ==15664== by 0x804B3E7: crashreport_handler (crashreport.c:495) ==15664== by 0xBB79AF: (within /lib/tls/libc-2.3.4.so) ==15664== by 0x804A9DD: main (calc.dasc:472) Note: see also the FAQ.txt in the source distribution. It contains workarounds to several common problems. If that doesn't help, please report this bug to: www.valgrind.org In the bug report, send all the above text, the valgrind version, and what Linux distro you are using. Thanks. [spc]lucy:~/source/jit>
Really Valgrind?
You don't support the INTO
opcode?
Wow …
Wednesday, September 09, 2015
“You've not experienced Shakespeare until you've read it in the original …”
I have a feeling that a limited number of readers may find this interesting, but I never know—more could find it interesting than I think. In any case, it's a two part video on an analysis of the play Hamlet. The original Klingon Hamlet!
Part 1 gives the background story for The Klingon Hamlet, giving a context for how it came to exist in the first place (along with a brief history of Klingons—not the fictional history of Klingons but the actual history of how the fictional race of beings known as the Klingons came to exist in Star Trek), as well as the construction of the Klingon language. It's interesting to note that Klingons consider Hamlet's speech in Act IV, scene iv to be (heh) the key speech of the play (“O, from this time forth, My thoughts be bloody, or be nothing worth!”), not Act III, scene i (“To be, or not to be … ” or in Klingon, “taH pagh taHbe'”).
Part 2 then goes onto a philosophical digression into translation in general. It's known in Geek circles that Klingon does not have the verb “to be,” and thus, the Klingon translation for “to be, or not to be” is literally “to continue, or not continue.” But there are issues with translating Hamlet into Spanish (two verbs for “to be”) or Mandarin (many forms of “to be”) and how difficult it can be to move cultural works across culture.
Oh my god! The radio just went to 11!
♫The bigger the cushion, the sweeter the pushin
That's what I said♫
“What?”
♫The looser the waistband, the deeper the quicksand
Or so I have read♫
“Wait a second … ”
♫My baby fits me like a flesh tuxedo
I like to sink her with my pink torpedo♫
“No! That can't be!”
♫Big bottom, big bottom
Talk about bum cakes, my girl's got 'em
Big bottom, drive me out of my mind
How could I leave this behind?♫
“My God! They're playing Spin̈al Tap on the radio!”
Thursday, September 10, 2015
Up-up and away
There's the story of the guy that strapped a large number of helium filled balloons to a lawn chair, just because he always wanted to fly. The modern variation today is strapping a large number of drones to a lawn chair, just because he always wanted to fly (link via Instapundit).
Neither variation appears safe.
Friday, September 11, 2015
In search of … the original Key Lime Pie recipe
It was while investigating reports of a ghost in the lavish mansion built by William "Bill Money" Curry in 1855 that Sloan encountered the original recipe for Key lime pie. "I heard movement on the floor above," he said, "but what stopped me cold was the recipe I saw in the pantry, the recipe for 'Aunt Sally's Key Lime Pie.'"
Sloan's early pie education came flooding back: "Most sources credit an anonymous 'Aunt Sally' with inventing Key lime pie. Well, it turns out that Aunt Sally was the cook at the Curry Mansion and as soon as I saw that paper, my heart started racing and I started to shake. I knew, I just knew. it was like finding the Golden Fleece, the Holy Grail."
Almost every family in Florida has a recipe for Key lime pie and they all claim it's the only authentic version. The filling is rarely disputed: Everyone agrees that green food coloring is for dry-landers and that a proper version is pale yellow. Rather, most debates revolve around the other two variables, crust and topping.
Battle lines in the crust camp are drawn between traditional pastry crust and graham cracker crust. The topping dissension is equally binary. Some believe that a lime pie can only be considered "Key" if modeling a lofty bonnet of meringue. Others argue that a slice of any self-respecting Key lime pie always sports a rakish dollop of whipped cream, preferably one that falls off to the side á la a French beret.
…
"There is no cream in the filling," he said. "There was never any cream. This pie was invented to use condensed milk. William Curry made his fortune in hardware. He provisioned ships. He brought the first condensed milk to the Keys not long after Gail Borden invented it in 1856."
The Curious Case of Key Lime Pie | Epicurious.com
Having lived in Florida for thirty-six years, I have learned that Key Lime Pie is pale yellow in color. I did not know that it originally used condensed milk (and it's odd to think that condensed milk has been available for 160 years!). I also did not know that Key limes are yellow, not green.
Saturday, September 12, 2015
Stories about a software company
Mercator Software, TSI International Software at the time, was my entry to the professional information technology (IT) world. It couldn't have come at a more interesting time, the peak of the dot-com bubble. We weren't a dot-com company, we were in business years before the Internet, but we were swept away by the madness. In a flash it was a billion-dollar company, only to sink in equally spectacular fashion. And there's me in 1998, last one in the office that unseasonably warm night, about to witness it all.
Semi-Disclaimer: My experience at Mercator is not comparable to the majority of employees who worked there over the years. I worked at the Bannockburn Illinois office which supported their line of EDI/B2B software. The home office was off in Wilton Connecticut and the flagship Mercator product line was developed down in Florida.
HuguesJohnson.com - The Abridged Story of Mercator Software
I'm finding it odd to read a story about a company I worked (however briefly) for. I was hired on as a contractor in Florida office in the mid-90s by a friend who worked there and my job at the time was to help port the software to various flavors of Unix popular at the time. I spent less than a year at the company and I probably departed long before Hugues Johnson started. Two things I remember about working there—one, the computer that ordered parts for itself, and two, the product produced cost anywhere from (I think) $1,500 (Windows version) to over $50,000 (for the computer that ordered parts for itself), and it was the same codebase. I remember thinking to myself, for $50,000 all you got was a 3½ floppy disk and one sheet of instructions? Shouldn't you get a bit more for that amount?
I still know two people who work on the project to this day (still in Florida, but they work for IBM). And the funny thing is—even though they both work on the same product, they've never met each other! (although they've heard of each other).
Sunday, September 13, 2015
Thread and a large red ball
It is impossible that this story be about anything other than a 3 ½- minute trick in the Penn & Teller show. It is a very beautiful trick that can’t be fully conveyed with words because it looks so simple: Teller makes a ball come to life. It isn’t a very exciting trick in that no knives, fire or risk are involved. A lot of their tricks have those.
And, to make matters worse, the trick I have the (partial) lowdown on, Penn doesn’t particularly like, or at least not until after he tells the audience how it is done—with a thread—before he walks off stage. And, therefore, yes, that’s right: This is going to be a story about a ball and a string—and Teller.
A man, a ball, a hoop, a bench (and an alleged thread)… TELLER! - Las Vegas Weekly
Bunny and I have been watching “Fool Us”, a television show where magicians attempt to fool Penn & Teller for a chance to play Las Vegas, but I guess it's also a means to showcase some pretty good magicians. At the end of each show they also perform one of their signature acts, and it's because of this you can see Teller's Red Ball Trick. Even knowing the secret doesn't diminish the skill and artistry involved.
Monday, September 14, 2015
I think there's a lesson here in simplicity, but I'm not sure what
Once upon a time, unbeknownst to each other, the "Automated Accounting Applications Association" and the "Consolidated Computerized Capital Corporation" decided that they needed the identical program to perform a certain service.
Automated hired a programmer-analyst, Alan, to solve their problem.
Meanwhile, Consolidated decided to ask a newly hired entry-level programmer, Charles, to tackle the job, to see if he was as good as he pretended.
Alan, having had experience in difficult programming projects, decided to use the PQR structured design methodology. With this in mind he asked his department manager to assign another three programmers as a programming team. Then the team went to work, churning out preliminary reports and problem analyses.
Back at Consolidated, Charles spent some time thinking about the problem. His fellow employees noticed that Charles often sat with his feet on the desk, drinking coffee. He was occasionally seen at his computer terminal, but his office mate could tell from the rhythmic striking of keys that he was actually playing Space Invaders.
Via Hacker News, The Parable of the Two Programmers
For some reason, I keep thinking back to making it look too easy. Strange.
Tuesday, September 15, 2015
Oh wait … this is an art project, isn't it?
This is a cool concept for a desk. Perfect for taking notes or doing quick sketches and very easy to clean, but you can't really keep anything on the desk. Well, you could but you would have to constantly rearrange items.
Perhaps if only half the desk were covered with paper …
Wednesday, September 16, 2015
It was twenty years ago today, that Crash Override taught us to HACK THE PLANET!
It’s the 20th anniversary of “Hackers,” one of only a handful of movies in the cybersecurity film canon. It occupies a strange place in an information security community that doesn’t traditionally suffer technical inaccuracy — “Hackers” is both beloved and technologically ridiculous. Two decades after characters Crash Override went swimming with Acid Burn, we’ve asked actual hackers, engineers, social critics, filmmakers, and even “Hackers” director Iain Softley to reflect on the movie’s influence and lasting appeal.
Via Hacker News, ‘Hackers’ at 20:
When I first saw the headline, I thought Wait? Isn't Hackers closer to thirty years old now?
But no, this isn't about the book, but the movie “Hackers,” the cheesy 90s movie staring Jonny Lee Miller and a pre-Brad Pit Angelina Jolie teaching us all to “HACK THE PLANET!!!111111!!!!!” I'll admit, it's always been a guilty pleasure of mine.
But really? Twenty years? It can't be! I remember seeing this in the theater! No way it was twenty years ago.
Now, where did I put my onion?
Thursday, September 17, 2015
Made from the heart of a fallen star and forged in the fires of a master smith is a knife that can even impress Anthony Bourdain
When it comes to chef, author, and professional foodie Anthony Bourdain, you never know quite what to expect, but you can bet your lucky stars it will make you feel inferior in every way. His latest blasé dive into cool, titled Raw Craft With Anthony Bourdain, is a collaboration with the The Balvenie Distillery that aims to dig up some of he world’s best-kept craftsmen (and women). In the latest episode, he heads to a workshop in Olympia, Washington to meld two of our favorite things: food and space rocks.
Knife maker extraordinaire Bob Kramer is one of just 122 recognized master bladesmiths in the U.S. His creations can fetch astronomical (no pun intended) prices at auction, in part because of the incredible detail that goes into making them, and because they’re made of meteorite. “When you think about it, they represent man’s first encounter with a solid chunk of iron – these star stones,” he says.
Via Instapundit, Anthony Bourdain Melts a Meteorite to Make a Beautiful Blade | Nerdist
It's not so much Anthony Bourdain melting a meteorite than it is watching
Anthony Bourdain watching Bob Kramer melt a meteorite to form an ingot of
steel from which he makes a custom, one of a kind, chef's knife that, if
you have to ask, you can't afford. You (and I) are probably not worthy of
even holding, much less using, this chef's knife is much
cheaper than I expected! I was easily expecting the price to be at
least twice that amount, so it's a relative “cheaper” not an absolute
“cheaper.” I was also not expecting it be to for sale through the Intarwebs.
Go figure!
Friday, September 18, 2015
Not feeling the love
I went to search for a post I wrote about a “Swedish programming language” (why? For reasons). I did what I usually do and search Google and got nothing (and adding quotes to the search term returned an explicit “No results! Ha ha!”). Sensing a pattern, I decided to hit Bing and … no results. And it appears that Bing ignores quotes around the search term.
I wanted this page! It even has the phrase “Swedish programming language” in the XXXXXXX page! (I finally found it by manually searching the site on my server)
Do Google and Bing no longer love me? Is it because I'm not encrypting all the things? Because I'm not running over HTTP/2? Or is the phrase “Swedish programming language” too obscure to bother doing a proper search? Oh wait! I know! It's because those pages weren't updated within the last twenty minutes!
Sheesh!
Breakin' the law! Breakin' the law! Scufflaws breakin' the law!
The 2015 Florida Statutes
Title XLVI CRIMES
Chapter 798 ADULTERY; COHABITATION
798.02 Lewd and lascivious behavior.—If any man and woman, not being married to each other, lewdly and lasciviously associate and cohabit together, or if any man or woman, married or unmarried, engages in open and gross lewdness and lascivious behavior, they shall be guilty of a misdemeanor of the second degree, punishable as provided in s. 775.082 or s. 775.083.
History.—s. 6, ch. 1637, 1868; RS 2596; GS 3519; RGS 5407; CGL 7550; s. 773, ch. 71-136.
Huh. How about that. (link from an ariticle about selectively enforced laws from Bob Anstett on FaceGoogleMyBookPlusSpaceTwitter).
Saturday, September 19, 2015
It. May. Cause. Paranoia. As. A. Side. Effect. How hard is that to understand?
The largest study of the effects of the main ingredient of cannabis has shown definitively that it can cause short-term paranoia. The Oxford-led research also, for the first time, identifies psychological factors that can lead to feelings of paranoia in people who take cannabis.
The research team, led by Professor Daniel Freeman, found that worrying, low self-esteem, anxiety and experiencing a range of unsettling changes in perceptions most likely led to the feelings of paranoia.
'The study very convincingly shows that cannabis can cause short-term paranoia in some people,' says Professor Freeman. 'But more importantly it shines a light on the way our mind encourages paranoia. Paranoia is likely to occur when we are worried, think negatively about ourselves, and experience unsettling changes in our perceptions.'
The study, funded by the Medical Research Council (MRC), is the most in- depth investigation ever of the paranoia-inducing effects of the main psychoactive ingredient in cannabis, THC (Δ9-tetrahydrocannabinol). …
How cannabis causes paranoia | University of Oxford
I shouldn't be posting this. Posting this is pouring salt onto a papercut already soaked in lemon juice, but the friend I lost over posting this on MyFaceGoogleTwitterBookPlusSpace (as a comment in another friend's post about an NPR report on the “War on Police”) probably won't listen to me any more and I feel this is actually important.
It's not like I want all drugs to be illegal (quite the opposite in fact, I want them to all be legal, and tax the crap out of it) nor do I like the resulting “War on Drugs” (Prohibi tion ultimately failed, giving rise to organized crime) but drugs do have side effects, and for marijuana, paranoia appears to be a valid side effect.
Sunday, September 20, 2015
The near futility of encryption key management
Contrary to popular belief, encryption per se isn't all that difficult. The algorithms are well known and hardened, and typically, the actual encryption APIs (the bits of the program that do the actual munging of the bits) are pretty easy to use.
It's the encryption key management that's near impossible to handle correctly. Key authorities are a joke. And even if the authorities in charge of encryption keys weren't a joke, it's still hard to exchange keys with random people and know your communications aren't being monitored, never mind obtaining your encryption keys via literal eavesdropping or through power consumption of your laptop (previous two links via tedu).
Monday, September 21, 2015
You had one job … and … you did it?
It's an exhaust port. It's to exhaust waste material, not suck it in. The fact that the Death Star blew up a planet means it generates a lot of waste heat that needs to be, how you say … exhausted? The Death Star Architect speaks out and he makes some very good points in his defense.
Tuesday, September 22, 2015
Even knowing the secret of a magic trick you can still appreciate the skill and artistry of the presentation
As I said earlier this month, even knowing the secret to a magic trick doesn't diminish the awe in watching the skill and artistry in presenting the trick. Even Teller says as much (link via Bunny). For example, although Penn & Teller are doing the classic Ball and Cups routine with clear plastic cups unless you are paying very close attention, the baseball that pops up at the very end of the trick is still surprising.
But wait! I thought you had to create the universe first!
$1,500 for a sandwich might seem an exorbitant amount of money for just a sandwich, but perhaps not, if you make it from scratch. And by scratch, I mean starting with wheat seeds and spending the next six months growing and collecting the rest of the ingredients (link via Jason Kottke). I think most of us would know where to get salt from (he gets it from three gallons of ocean water) but what about rennet to make the cheese? Or how to properly kill and dress a chicken?
The series makes me appreciate the modern food supply chain that exists. And the $1,500 price tag not only included the raw materials (about $500 worth) but his time (at minimum wage) spent directly making this sandwich.
Wednesday, September 23, 2015
It's … the Muppet Show?
Bunny and I watched the latest go around of the Muppet Show and … eh?
I perhaps found it just slightly more amusing than Bunny did, which wasn't much. The format of the show is no longer the Muppetonian chaos of a vaudevillian theater, but the back stage machinations (filmed as a reality television show complete with one-on-one camera interviews) of a talk show hosted by Miss Piggy who is no longer Kermit's girlfriend (which brings up a question—was she ever Kermit's girlfriend? The original show implied she had the hots for him, but he didn't reciprocate the relationship that much from what I could tell). Fozzie has a human girlfriend whose parents are … racist? Specieist? Muppetist? They don't approve of the relationship in any case and make what could be construed as racist remarks towards Fozzie (why is this even in the Muppet Show? Hello? Disney? Is anybody home?)
You know what? Disney could have taken the old 70s scripts and just slot in new stars. Instead of Alice Cooper, have Lady Gaga. Remove Steve Martin and replace him with Jack Black. Heck, replace Mark Hamill with … okay, you can redo Mark Hamill's episode with Mark Hamill—it'll still work.
Or heck, just rerun the original series again.
But I'm willing to give the new format another episode or two just on the off chance it finds its voice and becomes funny.
Thursday, September 24, 2015
It appears that my high school is now a day care center for delinquents
Coconut Creek High School was the first high school constructed in the City; built in 1972. With enrollment at 1,600, only 29% of the students are proficient in reading and 43% in math. 72% of the student body is considered economically challenged.
Via GoogleMyFaceTwitterPlusSpaceBook, What is your civic idea for Creek High?
My, how my high school has fallen (support for the statistics above). I remember back in 1986 (my junior year) Coconut Creek High School had five Silver Knight award winners, which is amazing when you consider there are only twelve awards given each year, and any senior in a Broward County high school can compete. It was a record at the time and one I think has yet to be broken.
It's sad to think how far down it has fallen.
Friday, September 25, 2015
Crazy Town
It was a crazy day today.
I had two tasks—drive to the local apothecary to pick up a prescription, then head to a local food establishment to obtain some provisions. So I'm pulling out of the driveway at Chez Boca when I see an amusing sight.
Now, Chez Boca is one house shy of the corner, so we're at one end of the block. Our neighbor righ across the street from us has a friend who comes over every Friday to hang out. Said friend lives at the other end of the block. I saw said friend drive from his house some 500 feet to our neighbor's house. I'm always amused when I see that.
Things proceed normally until I start to turn into the parking lot of the local apothecary. There's a driver who appears to be trying to turn into traffic, thinks better of it and starts to back up into the parking lot! I didn't think I was driving that fast that the best course of action was to back away from me as I approached. A few furtive glances, some wasted moments as we try to gauge each others actions, a revving of an engine and I'm past that obstacle.
Then there's the car parked haphazardly not only across two parking spots, but the end of the car was sticking out about halfway.
Sigh.
But that's nothing compared to this parking job:
But as always, it could have been worse.
Once inside and at the pharmacy, I was behind a woman who appeared to be in the process of purchasing a large number of candies and several large bags of chips. As the total was being rung up, the woman was getting more and more agitated as it appeared she did not have enough cash to enact the transaction. The pharmacist kept asking if she wanted to remove this item or these items, and each time the total still managed to exceed her ability to pay. A few minutes of this and the woman asked if she could go back to her car and search the seat cushions for change. The pharmacist said that was, indeed, fine. I was then able to obtain the prescription and leave the local apothecary.
At the local food establishment, I gave my order, two number elevens. The cashier punched a few buttons. I then said, “I'll take an unsweetened iced tea for the first order, and a chocolate shake for the second order.” The cashier stopped and looked as if I'd sprouted a second head.
“The first has an unsweetened iced tea, and the second has a chocolate shake,” I said again.
The cashier then proceeded to void the entire order. “You want?”
“A number eleven with an unsweetened ice tea,” I said. The cashier punched a few buttons.
“And?”
“A number eleven with a chocolate shake.”
A few more buttons were punched. “Okay, that's an unsweetened tea and a chocolate shake.”
“Um … could you repeat that order back to me?”
“A number eleven with an unsweet tea and a number eleven with a chocolate shake.”
“Yes.”
That done, I was handed a receipt to await my order.
“Hey, who ordered the sweet tea?”
Before I could answer, someone else behind the counter answered. “That was an unsweet tea!”
“Oh.”
Some moments pass. “Hey, who ordered the unsweetened tea?”
“I did.” Some more moments pass. “Um, I also ordered a chocolate shake.”
“You did?”
“Yes.”
“Okay.”
Several more minutes pass. I was then handed a tall cup topped with whipped cream. “This is a chocolate shake, right?”
“Yup.”
I left quickly and fought my way through rush hour traffic. As I was driving up to Chez Boca, I saw our neighbor's friend driving 500 feet from his house to our neighbor's house. Again. I'm always amused when I see that.
And the chocolate shake turned out to be a vanilla shake with caramel flavoring.
Is it a full moon or something?
Saturday, September 26, 2015
The fight for the smallest chess program is intense
Why would someone someone obsess over writing the world’s smallest chess program? Poudade has a complicated answer, involving paying his respects to a long-ago programming genius, drawing attention to his own coding group, and proving a thing or two to young-whippersnapper coders. That’s what motivated him to devote hundreds of hours to code what is ultimately a tiny black-and-white grid of text and numbers. Poudade’s chasing something like the Platonic ideal of computer chess programs.
He did something that mattered; he had the record. But, as they say, records are made to be broken.
Via Reddit, The bitter rivalry behind the world’s smallest chess program
Poudade's chess game is only 487 bytes in size, yet it's not the shortest chess program anymore, having an extraneous six bytes! And Poudade is not happy about that.
I didn't know the world of smallest chess programs was so cutthroat.
Sunday, September 27, 2015
It's the end of the world as we know it, and I feel fine
A perfect storm of religious prophecy, astronomical phenomena, global conflict, financial instability and natural disaster is conspiring to make this month’s “blood moon apocalypse” the most dreaded doomsday ever.
On Sept. 28, God and science will collide in spectacular fashion with the fourth lunar eclipse in just two years — a series known as a “tetrad” — each coinciding with a Jewish holy day.
The current tetrad of blood moons has fallen on April 14, 2014 (Passover), Oct. 8, 2014 (Feast of the Tabernacle), April 4, 2015 (Passover), and Sept. 28, which marks the first day of this year’s Feast of the Tabernacle.
According to the mongers of doom, this tetrad — the ninth to coincide with Jewish holy days since Jesus Christ — bears the signs of Old Testament prophecy heralding the end of times.
And the fourth and final of the lunar eclipses will also be a Super Moon, making it appear larger than usual and probably even more frightening to those convinced they’re about to meet their maker.
Via Instapundit, Doomsday prophets: Don’t buy green bananas with blood moon coming | New York Post
Ooh! It's the end of the world as we know it … again! Or … well, if not the immediate end of the world then the start of a long and painful process … maybe. Actually, if history is anything to go on, sit back, relax, have a Mai Tai, and enjoy the super blood moon.
Monday, September 28, 2015
Good for Oregon
On a recent afternoon, Ms. Walton was at a free legal clinic here in Oregon’s largest city, filling out paperwork to have that infraction forever sealed. Once the process is complete, she will be able to legally say to an employer, landlord or anybody else who asks that she has never been convicted or cited for any drug crime at all.
“It’s taken away a lot of my life,” Ms. Walton said as she inked out her fingerprints, which Oregon requires applicants for sealing to file.
…
Many states in the past few years have begun to rethink the implications of harsh drug or mandatory sentencing laws that led to high incarceration rates and costs, revising rules so people who have righted their lives can escape the stigma of a criminal record.
Ms. Walton used a state law, not restricted to drug offenses, that allows anyone with a lowest-level felony, misdemeanor or nontraffic violation to wipe the slate clean if 10 years or longer has gone by without another conviction. Starting next year, more serious felony marijuana convictions of the past, like manufacturing, will be eligible for record sealing as well.
Via Hacker News, Oregon’s Legal Sale of Marijuana Comes With Reprieve - The New York Times
I like to think that I do not have a “myoptic worldview” as some people have said. If I did, I don't think I would link to the above article about Oregon's experiment with legalizing marijuana and say that I applaud what Oregon is doing. I've held the belief that all drugs should be legal, just taxed at an insane rate. But otherwise, treat it as we do alcohol (although I'm not sure how I feel about drunks on horseback being arrested—I mean, doesn't the horse know the way home? The “drivers” aren't exactly “driving” the horse, are they? I don't think they should be arrested, or even stopped unless the horse is causing an issue. They're being more reponsible taking a sober animal home than in driving a heavy metal cage down the highway at speed. And how will this play out with self-driving cars? My, we live in interesting times indeed!).
“But Sean,” you say, “what about that post from the other day, about marijuana causing paranoia? How does that jibe with you wanting all drugs legalized?”
As with alcohol, there are benefits both good and bad to all drugs. In the case of that post from a few days ago, I was trying to point out (not very successfully I'll admit) that marijuana can change your world view, in potentially good or potentially bad ways. And maybe, just maybe, take it a bit more moderately.
Tuesday, September 29, 2015
The map that does not end
I like maps (and I have a large collection of road maps I've collected over the years), but I really like maps that are unusual or that have a unique projection, like the Dymaxion map (which can be folded up into an icosahedron) or the Upside Down World Map where north is at the bottom (north at the top appears to be a Western convention; maps of Japan by the Japanese tend to put east at the top, because that's where the sun rises).
But this linear map of Lake Michigan (link via Jason Kottke) is something I've never seen before. It's also continuous in that you can wrap the top edge to the bottom edge. Very neat.
No, it's the Muppets
Bunny and I watched the second epside of “The Muppets” (and not “The Muppet Show” as I related last week) and this time, it actually elicited a few chuckles from the both of us, giving the show another one episode chance. But they really do need to work on the Fozzie subplots. Fozzie as a souvenir taker-cum-kleptomaniac just didn't work—it had a rather painful ending.
But Miss Piggy and Josh Groban dating? That plotline was amusing.
Wednesday, September 30, 2015
Hey FaceGoogleMyBookPlusTwitterSpace, you're feaking me out!
“Hey, Bunny! Come take a look at this!”
“That's MyFaceGoogleBookPlusSpaceTwitter, isn't it?”
“Yup.”
“Hey! Didn't you just write a post about maps?”
“Yup.”
“That's why I don't have a GoogleMyTwitterFaceSpaceBookPlus page!”
Thursday, October 01, 2015
I get to deal with Transport Layer Security and email! Oh boy!
“Sean! Could you come look at this email?”
“Sure. Hmmm … ”
- From
- "Your XXXX Internet Customer Care Team " <customersupport@XXXXXXX>
- To
- "XXXX Internet Service Customer" <members@XXXXXXX>
- Subject
- Service Alert: Update your XXXXXXX computer email server settings before 10/14/15
- Date
- September 30, 2015 5:29:24 PM EDT
Service Alert: Update your XXXXXXX computer email server settings before 10/14/15
Dear XXXX Internet Service Customer,
Our records indicate that you are using an email application such as Microsoft® Outlook® or Apple® Mail to send or receive email using your XXXXXXX account. You'll need to update your XXXXXXX computer email server settings before 10/14/15 to continue accessing your email.
What Are Email Server Settings?
Your email server settings are used to connect Microsoft® Outlook® or Apple® Mail to your XXXXXXX mailbox. You are currently using outdated server settings to make this connection, and XXXX is discontinuing support of these on 10/14/15.
Why Should I Update My Email Server Settings before 10/14/15?
Your current email server settings will expire 10/14/15 and will no longer be supported by XXXX You’ll avoid service interruptions that will prevent you from sending and receiving email Updating to the new server settings increases both reliability and security
…
“Do you think this is a valid email?”
“Let me check the headers … ”
After a few minutes of scaning the raw headers, and doing a few whois checks on some IP addresses I was able to conclude the email was real.
And annoying.
Not because we had to spend the next five minutes reconfiguring Bunny's email server settings, but becauase that means I have until October 14th to work around this new twist in email when posting to my blog, as odd as that may seem.
My workflow for posting is to use my preferred editor to write the post,
then email it to my server where it will be posted via mod_blog
.
Now,
because I'm running Postfix (on Linux) here at Chez Boca
(just for updating the blog—I read email directly on my server using
mutt
… yeah, I'm weird that way)
it handles the delivery of email by queueing it locally, then forwarding it through our ISP's email servers
(because our ISP disallows direct email from home computers to arbitrary email servers due to spammer abuse).
So it appears I have about two weeks to figure out how to get Postfix at Chez Boca to connect via
SMTPS
instead of SMTP.
How hard can that be?
Um … yeah … looks like it'll take a while to get things configured …
Friday, October 02, 2015
With infinite resources one can even make pigs fly. It's still not a good idea.
Well the good news is that the test scores of New York City public- school students are up this year from last. The bad news is that still barely a third of them passed math or reading tests.
And that’s despite the fact that a number of teachers have been accused of tampering with test scores.
So what should we do? Teach everyone computer science!
Via Instapundit, The folly of teaching computer science to high school kids | New York Post
Strange as it may appear, I agree that teaching computer science to high school students is folly. Computers are (still) expensive (compared to books, paper, pens and pencils) and fragile. There's too much to fully understand (even I, who have been using computers for something like thirty years, still can't troubleshoot a Microsoft Windows issue, much to the dismay of my father who occasionally asks) and much of what is hot now goes out of fashion in a few years (over the past thirty years, I've seen the rise and fall of both Java and Perl, and Microsoft go from a juggernaut controlling the industry to a now mostly irrelevant bank with a quaint hobby in software, for example).
While I was in college, I saw the the first programming language taught in the computer science department change no less than three times! Back in high school, I took the programming course in Pascal (which is pretty much a dead language these days) on an obsolete computer (the Apple II back in the late 80s) and I was lucky in that I was able to use the only computer with two floppy drives! (which meant I could compile my code nearly twice as fast as other people in the class). And I can count on one finger the number of people who went on in life as a programmer.
And the sad thing is, computer science doesn't need computers to be taught. It's mostly math-centric theory. It's software engineering that requires the use of computers. Teaching “programming” is going to be expensive if you want to include all students. And I'm not alone in this view (link via Reddit).
Saturday, October 03, 2015
The Martian
Bunny and I saw “The Martian,” the movie about an astronaut being stranded on Mars and having to spend the next year or so surviving the harsh conditions. My understanding is that the book is about as accurate as you can get (with the sole exception of Martian sand storms aren't quite as bad as depicted, but the hero had to be stranded somehow for the story to work). I can understand that some concessions had to be made for Hollywood but still, this is some serious hard science in this movie, along with hard decisions that NASA wrestles with, dancing a delicate line between public relations success and disaster.
We both loved the movie, and feel it's well worth seeing Matt Damon coming home. Again.
Seriously, how many times does Hollywood have to save Matt Damon?
Sunday, October 04, 2015
An open love letter to Apple
Seriously, XXXX you, Apple!
Monday, October 05, 2015
About my open love letter to Apple
So … about yesterday …
iOS 9.02 hit the airwaves. I've been having an uneasy feeling about iOS 9 and I decided to wait a bit until things settled down. Normally, I'm all “if it ain't broke, don't fix it!” but there was an intriguing feature—the ability to block web ads! Which is an important feature if you're using the cellular network for browsing where each and every byte is accounted and billed for.
So, iOS 9.02 finally hit. What could possibly go wrong?
Twenty hours later, on phone support with Apple
“So what you're telling me is that there is no way Apple is going to let me dump iOS 9.02 on my own iPhone and roll back to iOS 8.4.1? No possible way? Is that what you're telling me?”
“Yes.”
“Aaaaaaaaaaaaaaaaaaaaaarrrrrrrrrrrrrrrrrrrrrrrrrrg!”
Ten hours earlier
Well, that was a disaster. I upgraded to iOS 9.02 and the second the iPhone rebooted, my version of iTunes dutifully informed me that it could not talk to my iPhone in question, and that I should upgrade iTunes if I wanted the ability to transfer data. Only thing is, there are no updates for iTunes I can download! There are no more updates for anything on my Mac computer. Remember “if it ain't broke, don't fix it?” Yeah. There's a reason for that.
I resorted to downloading iOS 8.4.1 off some random website (yes! I'm resorting to downloading possibly questionable software off the Intarwebs!) in an attempt to downgrade (look at what I'm resorting too, Apple! Why hast thou forsaken me?), but I couldn't get iTunes to install that version. It kept deleting the offered iOS 8.4.1 and kept shoving iOS 9.02 onto my phone. By the time I gave up, I had a phone without my music (not that I listen much music, but still), my contacts (which include custom ringtones for various friends and family members) and my apps.
That was totally unacceptable to me.
Had I been warned that iOS 9.02 would not talk to my version of iTunes, I would not have upgraded but alas, no mention was made in the Terms of Service (and yes, I read the whole thing) nor did iTunes give a warning until after it was installed.
On a whim, I downloaded the latest version of iTunes, just on the off chance I could run it. Good thing I checked before installing that, because it required a version of Mac OS X that I am currently not running.
What could possibly go wrong if I were to install that?
Don't answer that question!
Six hours later
If I can't solve it, perhaps the fine people at The Apple Store can help. I pack up everything I need and then some.
My iPhone.
My Mac mini.
My Mac mini power cord.
My iPad.
My iPad keyboard.
And some miscellaneous cables and adaptors.
All went with us (Bunny tagged along) to Mecca The Apple Store.
We found a very helpful employee who was both amused and sympathetic to my plight. While Apple itself wouldn't downgrade my iPhone (corporate policy it seems) he did help me figure out one issue with my failed attempts to reintroduce iOS 8.4.1 to my iPhone—my use of DoubleCommand.
You see, I use an IBM Model M keyboard. It's the only keyboard I use (I am very picky about my keyboards) but it lacks a “Command” key. So I mapped the “Alt” key to “Command.” Only Apple calls the “Alt” key the “Option” key. And it's the “Option” key you need to hold down when you click the “Restore” button in iTunes to select an iOS version to install. Unfortunately, I had deleted the iOS 8.4.1 images I had downloaded due to sheer frustration and therefore, could not install them at The Apple Store. But with this new information, I felt confident I could carry on back at Chez Boca.
Also, while at The Apple Store, we found a very unhelpful employee who was incredulous that I would dare not upgrade my Mac system every twenty minutes. “Everybody upgrades, dude! What ancient software relic are you running that you can't upgrade?”
“I'm running a special driver that allows my Mac to use my keyboard.”
“Macs don't use device drivers, dude!”
Sigh.
And by the way, I did end up using everything I brought along to The Apple Store. Even the iPad keyboard. The helpful employee felt it was best to try using that keyboard (after disabling DoubleCommand) so I could use a “real Option key” to select the iOS 8.4.1 image.
Four hours later
I finally found the right iOS 8.4.1 image for my iPhone. I was able to select it in iTunes. iTunes dutifully extracted it, contacted some license server at Apple, which nixed the attempt, due, I think, to the fact that Apple knows I've installed iOS 9.02 on the phone, and damn it! That's what I'm going to run! Apple wasn't having any of this iOS 8.4.1 nonsense. It's onward and upward!
Two hours past that
Brings us to the opening, wherein it's made clear by Apple that YOU WILL LIKE iOS 9.02 BEING SHOVED DOWN YOUR XXXXXXX XXXXXXX AND YOU WILL BE HAPPY, CITIZEN!
There is simply no way to downgrade to iOS 8.4.1.
(I would also like to note the very audible sigh I heard from Bob when I told him I refused to use iCloud for backing up my iPhone. I'd rather not have the iNSA view my iData without my iKnowldege. Is that so iWrong?)
I'm willing to conceed that most of this is my fault and that I brought it down upon myself for my refusal to upgrade everything Apple-related every twenty minutes, and that Apple even states they do not guarantee any software they write will actually work (that's actually standard in the software world). BUT it's my iPhone. I should be able to run what I want on it, as long as I take the consequences of said actions. And iOS 8.4.1 was working for me. I just wanted to downgrade to what was working less than twenty-four hours earlier.
But no, I do not, we do not, own our own computing devices any more.
I think it's time I swim out of the Nile and admit to myself that I am not the master of my own digital realm.
And that Apple owns my soul.
Tuesday, October 06, 2015
Nice job Apple! You narrowly avoided someone drunkenly spending tons of money!
After some discussion with Bunny about the past two days, I figured what the hell! Let me spend vast amounts of money to fix the problem! I repent! I'm sorry Apple! You are right! I am wrong! Let me upgrade everything and maybe, just maybe, I'll get a year or so reprieve from obsolescense!
So Bunny and I head back to The Apple Store so I could spend money like a drunken sailor on shore leave. Top o' the Line Macintosh computer! It's only money!
You know, I didn't think I'd be forced to wait half an hour to spend vast amounts of money, but then again, Apple has more money than God these days …
But wait I did. And while waiting, I looked at various Apple products and came to the conclusion that I really didn't need the Top o' the Line model—I could live with the K2 of Macintosh computers.
Eventually a helpful employee wandered my way, and I pointed to the K2 of Macintosh computers I wanted. “We can certainly sell you that.”
“But I want more memory in it,” I said.
“We certainly can't sell you that here.”
“What?”
“What you see is what you get. Custom orders have to be ordered on line.”
“Really?”
“Really. You can order it at home, and have it delivered at home, or you can select to have it delivered here at the store.”
“Oh.”
“But if you want, you can buy it online here.”
“Okay.”
So, why did I go to The Apple Store in the first place?
Yeah, that's right—to buy a computer!
Sigh.
I select the K2 of Macintosh computers and then get to the point where I need to sign in with my Apple ID. Only I don't remember my Apple ID password. Bunny saw the option to reset my password but that doesn't help me as I need to check my email to get a link to click to authenticate the request and yada yada short story I'm not in a position to check my email.
Double sigh.
So not only would I have to wait to get the K2 of Macintosh computers delivered, I couldn't even order it from The Apple Store! How lame is that?
A few hours later and I've come to my senses. I can upgrade the memory in my Mac mini from the paltry 2 gigabytes (Paltry! Ha! I remember the days when two gigabytes was considered gigantic. Sigh) upto 16 gigabytes, which is a heck of a lot cheaper than buying the K2 of Macintosh computers. I can upgrade to the latest and greatest operating system for free (and spend the next six months loathing every minute of it). And I get to keep the built-in DVD player!
I'll get my ring tones back yet!
Wednesday, October 07, 2015
John Cleese and Eric Idle: Together Again At Last … For The Very First Time
Months ago, Bunny bought tickets for a most unique show—John Cleese and Eric Idle: Together Again At Last … For The Very First Time at the Kravis Center for the Performing Arts. And lo, tonight was the night for the show. Given the past few days, it was just what I needed.
The only bad thing about the show (and it's not even that bad) is that it's only one-third of Monty Python and the sound quality. The two! The two bad things about the show were that it was only one-third of Monty Python, the sound quality and a ruthless efficiency. Three! Three bad things about the show are one-third Monty Python, the bad sound quality, a ruthless efficiency and a fanatical devotion to the Pope!
…
Anyway!
It was a fun show. In the first half of the show, John Cleese and Eric Idle spent the time chatting between themselves, performing a few sketches that never actually appeared on “Monty Python's Flying Circus” and showing clips from their past work (including stuff not from Monty Python, like “At Last the 1948 Show”).
The second half the show started with John Cleese telling … um … “off-colour” jokes (he's British, so I'm using the British spelling), followed by Eric Idle singing several … um … “off-colour” songs and then the both of them pulling “fan questions” out of a jar and pretty much mocking the questions.
The show concluded with everybody (Eric, John, and entire audience) singing “Always Look On The Bright Side Of Life.”
It's either a small world, or we have very similar tastes in entertainment
Much like when Bunny and I saw Alton Brown and Jamie and Adam, we ran into my old roommate Rob, his wife Laura, friend Squeaky and his wife Tanya (and had I not lost my phone contacts, I would have texted Rob this time). I wonder if we'll run into them again when we see Shatner's World or Penn & Teller?
Thursday, October 08, 2015
You know his music will be the only music of our era to survive, right?
It's not singing as we know it. But it's not exactly a spoken piece either. The closest thing is similar to watching a train wreck in real time—horrifying and yet, completely fascinating at the same time. I am, of course, talking about William Shatner “covering” Bohemian Rhapsody (and you can thank Bunny for that link). But I think I like his “covers” of Space Oddity and it's sequel, Major Tom (Coming Home) a little bit better.
Friday, October 09, 2015
Wow … and you thought the Edsel was a bad car
The fuel line goes through the cabin. The side windows are raised and lowered by a leather strap. The wheelbase is shorter than the width of the car. And you can't see the side mirrors from the driver's seat. There's even more bad, but yes, this is a bad car (link via Instapundit).
Saturday, October 10, 2015
Good intentions with bad implementations should be outlawed! Oh wait … they are!
I'm sitting,
futzing around on the computer.
Bunny is in the other room,
watching television when this horrible buzzing noise starts.
I'm thinking,
Is that
the Emergency Broadcasting System
I mean
the Emergency Alert System?
I don't think I've ever heard it in actual use,
when I realize it's coming from my phone and it's an Amber Alert sent by the government.
Oh. I can get these on my iPhone now. Which tells me to be on the lookout for a certain type of vehicle of a certain color, which is only applicable if I'm out, driving about, but Florida law makes it illegal for me to actually check my cell phone while driving!
Lovely!
Sunday, October 11, 2015
Stuff you don't learn in history class
Wisconsin last week closed a haunting chapter of the Cold War that began when Svetlana Alliluyeva famously defected to the U.S. in 1967.
But to her daughter in Portland, the death of the woman who became known as Lana Peters was the loss of her best friend and confidant.
Huh.
I never knew Stalin's daughter defected to the United States. And I wonder what it's like to grow up with such an infamous grandfather like that …
Monday, October 12, 2015
El Capitan is the captain around here, not me
One week ago, I wrote “[b]ut no, I do not, we do not, own our own computing devices any more.” The context of my saying that was in the forced “thou shalt not downgrade thy iPhone” I received from Apple but it's becoming more apparent that I don't “own” my Mac mini either—it's that Apple has benevolenty allowed the use of their Mac mini by yours truly.
I've just now learned about
the System
Integrity Protection “feature” that El Presidente de Por Vida
Capitan contains
(really Apple?
Another series of pointless names for operating system releases?
What,
exactly
is so wrong with 10.11?).
root
is no longer root.
Yup,
not even root
can delete all of /sbin
,
not that you would want to do that,
but the point is—Apple is making damn sure you,
as “owner” of the machine,
don't go deleting files willy-nilly.
Of course Apple can delete files willy-nilly on “your” machine,
because they know better.
And really, it's not quite as dire as I make it out to be (it can be disabled—link via Reddit). I can understand why Apple does this—to protect users from malware but I feel as if I don't actually own my computer. And now I'm just a bit more wary about upgrading my Mac mini (as I sit here, looking at the “Install El Presidente de Por Vida” icon, just waiting for the 16G of RAM to arrive).
Sigh.
Tuesday, October 13, 2015
The calm before the storm
Woot! The 16 gigabytes of memory arrived! It's been installed and it's working beautifully. I'm currently backing up the Mac mini and when I work up enough courage, I'll do an incremental backup in the hopes that it takes longer than my courage holds up, then wait a bit more and eventually, the incremental backup will be over so quickly I'll have nothing left to do but update to El Presidente de Por Vida.
Wish me luck.
An appropriately Halloweenish thing to do
This is wonderful! This is a great idea for a drone!
Wednesday, October 14, 2015
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
XXXX you, Apple. XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX you, Apple!
No, seriously, you can go XXXX yourself, Apple.
The backup? Went smooth. And way faster than I expected. The upgrade to El Presidente de Por Vida? It took longer than the 30 minute estimate it gave, but eh, I can live with that. And my files were still there. That's good.
Less good? Oh, let's see … I had statically set the IP address of the Mac and Apple blew that setting away. Good one! I had a VPN configured for work, operational word there being had. Apple blew those settings away.
Apple also deleted everything I had under /usr/local/bin
.
XXXX you, Apple.
So there went my only OS X compiled version of Synergy.
Have I told you to XXXX off yet, Apple?
No?
XXXX off.
I still had the source, but guess what?
source='CArch.cpp' object='CArch.o' libtool=no \ depfile='.deps/CArch.Po' tmpdepfile='.deps/CArch.TPo' \ MACOSX_DEPLOYMENT_TARGET=10.2 depmode=gcc3 /bin/sh ../../config/depcomp \ g++ -DHAVE_CONFIG_H -I. -I. -I../.. -I../../lib/common -g -O2 -g -Wall -Wno-unknown-pragmas -Werror -DSYSAPI_UNIX=1 -DWINAPI_CARBON=1 -D_THREAD_SAFE -c -o CArch.o `test -f 'CArch.cpp' || echo './'`CArch.cpp In file included from CArch.cpp:16: In file included from ./CArch.h:25: In file included from ./IArchString.h:19: ../../lib/common/BasicTypes.h:78:10: fatal error: '/System/Library/Frameworks/CoreServices.framework/Headers/../Frameworks/CarbonCore.framework/Headers/MacTypes.h' file not found #include </System/Library/Frameworks/CoreServices.framework/Headers/../Frameworks/CarbonCore.framework/Headers/MacTypes.h> ^ 1 error generated. make[3]: *** [CArch.o] Error 1 make[2]: *** [all-recursive] Error 1 make[1]: *** [all-recursive] Error 1 make: *** [all] Error 2
Yeah! Screw backwards compatability! That only leads you to legacy hell ala Microsoft.
To be fair, even if I had the executable it probably wouldn't have worked, but man … that is a serious blow to my work flow here at Chez Boca. Not only the ease of sharing a keyboard and mouse between two computers of differing operating systems, but cut-n-paste! Cut-n-paste between the two operating systems!
I did download the latest version
(although you won't find that link on the main Synergy website)
but it requires some manual “fixes” to the source code that have yet to be checked in
(really?
Seriously,
what the XXXX?)
and of course it requires yet another build system
(really?
You can't even make cross-platform Makefile
s?
It's not that hard.
Tedious,
I'll give you that,
but that's like a one-time thing.
XXXX!)
and a large “cross-platform portability library” and XXXX me,
this means it probably isn't backwards compatible with the version on my Linux system and I'll have to upgrade that too because of CADT
XXXX me XXXX me XXXX me XXXX me XXXX me XXXX me XXXX me XXXX me XXXX me XXXX!
XXXX!
Okay, so maybe Apple isn't the only thing trying to XXXX me over.
[Ooh … my bad—Apple did NOT delete everything. –Sean]
Well. That felt good. Now to email this … oh wait …
XXXX!
iCloud this and iCloud that. What about uShutTheXXXXUp!
On the plus side, I have finally restored my iPhone. Of course, to do that, I had to disable “Find my iPhone” before iTunes would restore my iPhone. If course, when you do that, you get this friendly email from Apple:
- From
- Find My iPhone <noreply@insideicloud.icloud.com>
- To
- sean@conman.org
- Subject
- Find My iPhone has been disabled on iPhone.
- Date
- Wed, 14 Oct 2015 03:48:57 +0000 (GMT)
Find My iPhone has been disabled on iPhone.
With Find My iPhone disabled, this device can no longer be located, placed in Lost Mode, or remotely erased using icloud.com/find or the Find My iPhone iOS app.
In addition, your Apple ID and password will no longer be required for someone to erase, reactivate, and use your iPhone.
--
iCloud is a service provided by Apple.
Apple ID: https://appleid.apple.com/choose-your-country/
Support: https://www.apple.com/support/icloud/ww
Terms and Conditions: https://www.apple.com/legal/internet-services/icloud/ww/
Privacy Policy: https://www.apple.com/legal/internet-services/privacy/
Copyright 2015Apple Inc. 1 Infinite Loop, Cupertino, CA 95014, United States. All rights reserved.
XXXX you too, Apple!
Apple is really pushing the iCloud thing. Really pushing it. Like, “you know you'll be XXXXXX if you don't use this, right?” pushing it.
No, I do NOT want to use it. And yet, I have to keep telling Apple that over and over and over again as I run various applications.
Sigh.
I leave this without comment
Thursday, October 15, 2015
… and then the router broke
The badness kept going yesterday.
As I was getting ready for work, Bunny informed me that she had to reboot both the DSL modem and the router. When I checked them, the lights on the router were off. Not a good sign. I pulled the power cord and plugged it back in, the lights started operating normally, then they went out, back on, went out, back on, and well, it's not supposed to be blinking Christmas lights. Bunny mentioned that on Tuesday there were a few power fluctuations and maybe that fried the electroncs.
It was then that the past month of computer aggrivation hit me and I'm afraid I took it out on the malfunctioning router (well, I assume it was malfunctioning; it certainly was malfunctioning after I was done with it). Bunny then asked if I was okay to drive to work, I said no, so she offered to drive. Only I couldn't engage the seat belt.
I took it as a sign that “the Universe” was telling me it was a bad week to stop taking meth, called in sick, and went back to bed.
At 5:00 pm, I awoke, and Bunny and I headed out to get a new router and UPS. A couple of hours, several hundred dollars, a few stores, and many many miles later I was trying configure the new router and was not having luck. It wanted an Internet connection (I'm trying to set you up first before placing you on the live Internet you incalcitrant piece of consumer electronics!) It then started asking for a password I didn't have!
There was this CD included with the router—perhaps it had the instruction manual? Sure enough, it did. The only file on the disk, a large PDF of the manual.
In Arabic!
It was at that point that Bunny sent me to bed before I caused any more collateral damage.
I awoke at 2:00 am this morning. Bunny had tried quite a bit to get the router working. Using the “hot spot” feature of her iPhone, she was able to surf the Intarwebs for an English version of the manual but quickly got to a point she didn't feel comfortable with. I started poking with it again and well … bless her heart, Bunny had the patience to deal with our ISP technical support to get us up and running again. That email we received on the first? Yeah, more than just the email server changed. Turned out we needed a new password to log onto the Internet but it took an hour long phone call to figure that out.
So I have my iPhone restored, my Mac upgraded, and our Internet connection restored. Synergy isn't working, but I think at this point, I should stop complaining.
I think my long October nightmare is finally over
My friend, Brian, concerned for my sanity, did some searching and sent me this:
- From
- Brian Yoder <XXXXXXXXXXXXXXXXXXXXXXX>
- To
- Sean Conner <sean@conman.org>
- Subject
- El Capitan: Rootless "feature"
- Date
- Thu, 15 Oct 2015 14:23:33 -0400
From: http://apple.stackexchange.com/questions/193368/what-is-the-rootless-feature-in-el-capitan-really
When you upgrade to El Capitan, it moves any "unauthorized" files from restricted areas to
/Library/SystemMigration/History/Migration-
(someUUID)/QuarantineRoot/
.
Really?
[spc]marvin:~>ll /Library/SystemMigration/History/Migration-0C65E56F-4185-42B0-BBE8-5537E4FDEE38/QuarantineRoot/usr/bin/ total 92472 -rwxr-xr-x 1 root wheel 60212 Dec 6 2005 bbdiff -rwsr-xr-x 1 root wheel 86416 Dec 6 2005 bbedit -rwxr-xr-x@ 1 root wheel 21226488 Feb 4 2005 emacs (from old Mac) -rwxr-xr-x@ 1 root wheel 21226488 Feb 4 2005 emacs-21.2.1 -rwxr-xr-x 1 root wheel 1511312 Dec 21 2010 pkgbuild -rwxr-xr-x 1 root wheel 1605200 Dec 21 2010 productbuild -rwxr-xr-x 1 root wheel 1440848 Dec 21 2010 productsign -rwxr-xr-x 1 wlofie staff 1195132 May 14 2010 synergyc -rwxr-xr-x 1 wlofie staff 1751764 May 14 2010 synergys -rwxr-xr-x 1 root wheel 3561 Jul 12 2007 zegrep (from old Mac) -rwxr-xr-x 1 root wheel 3561 Jul 12 2007 zfgrep (from old Mac) -rwxr-xr-x 1 root wheel 103 Jul 12 2007 zless (from old Mac) [spc]marvin:~>
Oh.
There are my missing executables!
In /usr/bin
!
And … owned by wlofie?
How did—
Nevermind!
I found them!
I had to copy them out of that directory to $HOME/bin
so they won't get blown away again.
Then I had to tweak “System Preferences → Security & Privacy → Privacy” to allow Terminal
and “sshd-keygen-wrapper” to have control over my computer,
then I can run synergys
in the foreground,
and it works!
If I let synergys
run in the background
(as it does by default)
then El Presidente de Por Vida prevents it from doing anything useful.
But I got it to work!
So now I'm back to where I was on October 1st!
Woot!
Friday, October 16, 2015
Phones for the people
I feel that this small video about phones designed for people, and not for companies, somehow plays into our (the West) uncaring acceptance of modern computing and not demanding more control over what we buy and use. I'm not quite sure how it plays, but I definitely feel like it does. Who wouldn't want a phone to look like a race car?
Saturday, October 17, 2015
It's more a laser cutter/laster etching machine than a printer, but it's still very cool
The Glowforge 3D Laser Printer is way cool! Even though it uses the cloud for just about everything, it's one way that Glowforge has kept the price to the very low four digits instead of the five digits normal laser printers/cutters apparently go for. And here's an interview with the head of Glowforge about the device.
Too many moving parts
Ever since I got the new router, I've been having some weird issues with browsing. Most sites would come up instantly while others, like Hoade's, would take minutes to come up, and when the page would finally display there would be horrible formatting (probably due to not loading the style sheets).
This behavior is a classic DNS problem. But the only thing that changed, DNS wise, is the introduction of the new router. Is it possible the new router is filtering DNS results? I did a query on a problematic address and got:
[spc]lucy:~/source/spcdns/built>./dotest -s 192.168.1.10 use.typekit.net. a ; Questions = 1 ; Answers = 1 ; Name Servers = 0 ; Additional Records = 0 ; Authoritative Result = false ; Truncated Result = false ; Recursion Desired = true ; Recursion Available = true ; Result = No error ;;; QUESTIONS ;use.typekit.net. IN A ;;; ANSWERS use.typekit.net. 3600 IN CNAME cs485.wac.gammacdn.net. ;;; NAMESERVERS ;;; ADDITIONAL
Hmm … now let's do the same query from somewhere else:
[spc]brevard:~/source/spcdns/built>./dotest -s 70.34.22.227 use.typekit.net. a ; Questions = 1 ; Answers = 2 ; Name Servers = 2 ; Additional Records = 0 ; Authoritative Result = false ; Truncated Result = false ; Recursion Desired = true ; Recursion Available = true ; Result = No error ;;; QUESTIONS ;use.typekit.net. IN A ;;; ANSWERS use.typekit.net. 3600 IN CNAME cs485.wac.gammacdn.net. cs485.wac.gammacdn.net. 3600 IN A 192.229.163.37 ;;; NAMESERVERS gammacdn.net. 127697 IN NS ns2.gammacdn.net. gammacdn.net. 127697 IN NS ns1.gammacdn.net. ;;; ADDITIONAL
Odd. And annoying. Doing a search on DNS issues with my router was dismaying to say the least. First off, the pages would take minutes to load and thus, no style information and thus hard to read. Secondly, from what I could read, there actually might be an issue with DNS on this router. Lovely!
But in playing around with this stuff, I did find this comment in the DNS server configuration file:
/* * If there is a firewall between you and nameservers you want * to talk to, you might need to uncomment the query-source * directive below. Previous versions of BIND always asked * questions using port 53, but BIND 8.1 uses an unprivileged * port by default. */ query-source address * port 53;
I know I added that comment, fixing an issue with DNS a few years ago. Really? Could that be the problem? Let me comment that directive out … and it's all fixed!
What the—
Okay, I've done some research, and it also revealed another issue I noticed with the new router. Network devices obtaining network information via DHCP were getting the router's IP address for DNS, not my actual DNS server. It appears that Linksys decided to direct all DNS traffic to the router and have it query the DNS server. It may have something to do with their “cloud” offering (so you can configure your router remotely—do people really want this feature?) I don't know. But it's a weird way of handling DNS. And having queries come from port 53 may have been confusing the router.
When I try it now (the the previous DNS server configuration) I get:
[spc]lucy:~/source/spcdns/built>./dotest use.typekit.net. a net_request() = Connection timed out
I think I can explain this difference between the two results. I switched out the router but the DNS server was still running. Over time, certain DNS records expired and thus, not all the required information could be returned. The DNS server was getting some weird packet (more on that below) and just returning what it could at the time. Restarting the DNS server flushes all existing records and because of some weirdness with the router and DNS, some queries are just … lost … somewhere … over the rainbow.
I don't know, I don't have the source code to the router to troubleshoot—
Sorry about that. Bunny came in and said she couldn't get Netflix on the “smart” television. What the hell?
One hour and much cursing and angry shouts later, it's working. How? I dunno. All I want it a dumb wireless pipe to the Intarwebs. I don't need this “user friendly” crap router to intervene on my behalf. Is that so wrong?
Sunday, October 18, 2015
El Capitan is the captain around here, not me, part deux
I thought it’d be a “fun” project to see what the “El Capitan License” actually says. Cool idea, huh? Kind of like spelunking through a cave that everyone says they’ve been through, but maybe no one really has. What will I find wedged in a wall or lurking in the dark around the next turn?
- I can’t use the Capitan with illegal copies of anyone’s stuff.
- Apple didn’t sell me this software. They still own it, in fact. I’m just borrowing it.
- If I install more Apple software, those are on loan as well.
- …
Via Hacker News, OS X El Capitan License: in Plain English | The Robb Report
Hmm … I guess I was more right than I thought …
… and then the router cable broke
I swear … is this ever going to end?
Um … end well?
Monday, October 19, 2015
A keyboard that might be tolerable to use
The Ultimate Hacking Keyboard (link via Lobsters) has a unique design, looking like a slightly-undersized normal keyboard but one that can split in half to allow for ergonomic positioning. It also split the spacebar in half, with the right side being the spacebar, and the leftside being another modifier key (personally, I would map the modifer key to backspace—it makes sense to me). I'm also glad to see them use a real mechanical switch with various models having differing “stiffness” factors (I really like the clicky keyboards). I do like the ability to mimic the mouse from the keyboard though.
The price, however, is a bit on the high side. But then again, I haven't spent more than $20 for a keyboard (even used, the IBM Model M are solid enough to bludegon lusers with and yet, have a wonderful feel, if they are bit “clicky”).
Tuesday, October 20, 2015
Notes on a conversation held at 4:00 am
“Um … Bunny? I think there's a creature in the room.”
“Really?”
“You didn't hear it?”
“Hear what?”
“A … an … unearthly chirping…esque … sound, like a wounded dodo bird.”
“Dodo's are extinct—how do you know what they sound like?”
“How do you know what they don't sound like?”
“Touché.”
“Listen … ”
[One snooze period passes]
“I haven't heard anything.”
“Give it some time.”
[Another snooze period passes]
Scriiiieeeeeeeeeeeeeeeeeeeeiiiiiiiiiiiiii…
“Did you hear that?”
“I … think … so … ”
Scriiiiieeeeeeeeeaaaaaaaaaaaaaaaaaaaaaaaaaiiiiiiiiiireeeeeeeeedruuuuuuuuummmmmmiiiiiiiii…
“THAT!”
“Oh, that! It's just the bougainvillea scraping against the window.”
“Bougainvillea?”
Scrriiiiiieeeeeeeeeeeeeeeeeeaaaaaaaaaaaaiiiiiiiiiiiiiiiigeeeeeeeetoooouuuuuuuutoooooooooooiiiiiaaaaa…
“Yes. Definitely the bougainvillea.”
“Well, if that's all it is then … zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz”
Wednesday, October 21, 2015
Funny, it doesn't feel like the future
The reason [Marty] sets the DeLorean to Oct. 21, 2015? It’s the day 30 years in the future when the Cubs are predicted to win the World Series. Bob Gale, who scripted the 1985 original with Robert Zemeckis, said that he tried to figure out when the final game of the Series would have played: “I did my homework as a baseball fan.”
Marty McFly Returns! : snopes.com
But the Cubs are down three games and we still don't have hover boards.
Sigh.
Thursday, October 22, 2015
Darth Vader is still the good guy
Wait a moment. Do you even know the difference between the light side and dark side of the Force?
It must be understood that the Force is, above all, singular. The so- called "sides" arise from differing matters of perspective. (If you study the way of the Sith you will find that many of the truths we cling to depend entirely on one's point of view.)
The opposite of the singular Force is the all-encompassing void of death. Time began with the Force, and will end in desolation. This is the way of things, and an inevitable consequence of the flow of events from the past into the future.
Without the inertia of the fall toward the abyss, the Force would have nowhere to go.
For in the chaotic tumble toward doom the stuff of the worlds enact loops of complexity that change the grade from life to death, introducing valleys, peaks and cycles. Between creation and destruction comes a flutter of improbability, a brief sonnet of meaning against the noise of time. Life!
It is the causal contagion that ties every ounce of us together through the network of the Force, our actions resonating against our almost-actions and our non-actions in a web of fleeting possibility that spans this galaxy and beyond. The beat of a child's heart detonates supernovae, the beat of a bug's wing tilts the orbit of worlds.
We are all connected.
Anyone who awakens to the Force knows this. The divisive issue is what to do with this knowledge.
When you can run the mechanism of the universe forward or backward, scrubbing through possible histories with a thought, a theme develops. You cannot escape it. Death, death, death. It is the final destiny of all things, great or small, matter or idea. But there is astounding beauty in the arts of the not-death, the filigree dances of life's loops as it spins from light to void. If you are human, it moves you.
It should move you. But this is what the Jedi Order denies. They preach that the heart of a beast cannot judge the destiny of a galaxy. They preach dispassion and detachment, a condescending compassion for the damned. They stand by the sidelines and watch history happen, intervening only in trivia that offends their effete sensibilities.
Every Jedi knew the cycles of civilization, and every Jedi knew an age of barbarism was nigh. And yet they did nothing.
Via Decline and Fall of the Empire | The Weekly Standard (which in turn I got to via Instapundit), The Darth Side: The Tao Of Sith
If you really think about how George Lucas wrote the story, it becomes apparent that “the Good Guys” (that is, the Jedi Knights) not all that nice while “the Bad Guys” (the Empire) are apparently the only force keeping the galaxy from falling into barbarism.
Friday, October 23, 2015
I, for one, will welcome our new AI overlords
Earlier this year, I was driving in a northern Michigan snowstorm headed to Detroit airport. I was worried that, given the storm, my flight might be delayed. Thusly, I grabbed my phone and without knowing if it would work I said to it:
"OK GOOGLE, what is the status of my flight today?"
Within seconds, Googlebot (or maybe it was Larry Page - not sure) responded:
"Flight XYZ from Detroit, Michigan to San Francisco, California is scheduled to leave on-time at 2:30pm".
Pretty cool huh? If you were like me, you're sort of thinking that was cool but big deal, it should do that. OF COURSE it should do that - I could have done that (had I not been driving). After a lot more thinking about it however, I'd like to point out that boy are we a snot-nosed, ungrateful species who take amazing things for granted.
A stunning array of technologies just came together to make that happen. So much so I'm convinced I could write a full length blog article just listing them. In the name of sticking to the topic (i.e. complete human destruction caused by the emergence of AI) let's take for granted the everyday sorcery of talking to thousands of computers around the world, I'll just focus on the “artificial intelligence” parts. (Where “intelligence” may have a fuzzy definition).
Simply: I spoke to my tiny hand-held computer in English. It heard me start with "Ok Google" to know I was addressing it. It then parsed the rest of my words and realized I had asked a question (it likely offloaded that work to a remote computer). It is also able to recognize the voice of millions of others speaking in accents and dialects. I could have likely phrased that question many ways and it still would have worked. It parsed my question and understood I was asking about a flight. It then scanned my Gmail to find my flight reservation I had made months before. From that it examined the outbound and return flight and realized the outbound had already happened.
It might have realized my current location was in Michigan near(ish) the Detroit airport further understanding I was asking about my return flight. It then hit some real-time flight database to know if the flight was still on time. It might have checked Detroit Airport in general for delays to decide if it should respond in a qualified manner. It then formulated a perfect English sentence, maybe with considerations of how I formulated my sentence, computer generated the audio in a human voice, and played it aloud for me.
Go ahead, be not impressed - I dare you. Clichés be damned. We truly live in amazing times.
So that's now. What's coming next? How about:
"OK Google, what's the probability my flight will crash today?"
Via Lobsters, Paul Tyma: How Artificial Intelligence Will Really Kill Us All
The good news? That Paul Tyma doesn't think we'll face the Terminator Scenario.
The bad news? It's much, much worse.
Saturday, October 24, 2015
Ozymandias
Given the problems I had earlier this month, I found this poem (via Violet Impudence) quite appropriate:
I met a programmer the other day
Who said “A vast and blocky plastic box
Stands in my workspace; in it, so they say
Half-dead, a chip from Intel lies, which clocks
566 M-hertz; the CD drive
And fifteen gigs, and bundled AOL
Must have seemed neat when Reagan was alive
But now the stickers on its lifeless shell
Seem only fit sad memories to revive
And on the light beige case are words that say:
“THIS COMPUTER IS NEVER OBSOLETE
SURF! INVEST! EMAIL! TYPE! SHOP! TRAVEL! PLAY!”
The monitor is dark; near its defeat
My new and shiny MacBook whirs away
There's even a photo of the non-obsolete computer in question.
Sunday, October 25, 2015
Notes on an overheard conversation while watching an interview with Bill Clinton
“Have you seen Bill Clinton recently?”
“Yeah, he's very thin and looks old.”
“He's not that old though.”
“I guess being married to Hillary will do that to you.”
“I guess so.”
Oh, it's the expression problem
Years ago I blogged about an observation I had about the main difference between procedural programming and object oriented programming, mainly, that procedural programming emphasizes actions (or “verbs”) while object oriented programming emphasizes data (or “nouns”) but there currently exists no programming language that allows one to expand both easily. It's not a unique observation, but it wasn't until today that I learned it actually has a name—the expression problem.
And there's still no programming language that allows one to expand both easily at the same time.
Monday, October 26, 2015
As painful as it sounds, the DOJ's argument to Apple is compelling
The Department of Justice is trying to get Apple to unlock a defendant's iPhone. While Apple has stated that it can technically bypass the phone's passcode security, it has so far refused to do so for various reasons. So the DOJ has come up with a new strategy, force Apple to comply because it licenses the software on the phone. Because of that, the DOJ contends that the iPhone maker actually has a relationship with the phone that's currently evidence in a case. In a reply to Apple's response to the court order to unlock the phone, the government states, "Apple cannot reap the legal benefits of licensing its software in this manner and then later disclaim any ownership or obligation to assist law enforcement when that same software plays a critical role in thwarting execution of a search warrant." In other words, it's your software Apple, not the defendant's, unlock it.
The government's strategy is a reaction to Apple's refusal to comply with a court order to unlock an iPhone 5s. In its response to the order Apple lawyers stated, "forcing Apple to extract data in this case, absent clear legal authority to do so, could threaten the trust between Apple and its customers and substantially tarnish the Apple brand." It also noted that unlocking the phone would eat up resources and might not even yield any information. Plus, just for good measure, it would be impossible to circumvent the passcode of any iPhone running iOS 8 and later. The phone in question is running iOS 7.
As expected, the government isn't too happy about not having access to the phones of defendants. Apple CEO Tim Cook has been on a privacy crusade recently. He recently said that people have a, "fundamental right to privacy." Cook has also insisted that the government does not have a backdoor into Apple's servers.
Via Reddit, DOJ: Apple owns your iPhone's software, so it should have a backdoor
Ooh! Pass the popcorn! This is going to be fun to watch!
Apple says I'm just borrowing their software, and now the DOJ is saying, “fine, it's your software, you let us see this data generated by your software! Fork it over! It's not while-collar resort prison you'll be seeing … ” And now Apple is in a bind, between “selling” its code (and thus, making it fall under the first sale doctrine—something most software companies try to avoid to make as much money as they can) or continue to “license” it and thus, be forced by our beloved government to hand over private information (thus making them hypocrites to their customers and potentially losing money).
The road to the Sith is paved with good intentions
I’ve had this argument with friends so many times; some think as I do, others remain convinced that Luke ended the original trilogy as a Good Guy.
I say he, in fact, had turned to the dark side and we watched it happen in blissful ignorance, choosing to believe that he would always be The Good Guy. Lucas wanted it this way so he could sell more toys. But there’s way more to this story.
Seeing these previews I think my theory might be correct: Luke gave in to the dark side to save his friends and defeat Vader and the emperor. We don’t know what will happen after that, and hopefully we’ll find out in December and we’ll see if I’m right.
Here are my arguments, in no particular order…
Via Jason Kottke, Luke Skywalker, Sith Lord — Medium
Read the article, and then think back to Luke's actions in “Return of the Jedi.” Given the original storyline outlined in the article, it's quite believable that Mark Hamill played Luke as a Jedi falling to the Dark Side. Did Darth Vader take pity on his son and kill the Emperor? Did Luke subtly influence his father to kill the Emperor? Did Luke outright manipulate Vader to kill the Emperor?
I'm trying hard not to have high hopes on “The Force Awakens” because Lord knows how disappointing “The Phantom Menace” was, but George isn't heading this movie, and the last time that happened we got the best Star Wars movie made.
Tuesday, October 27, 2015
Is HR expecting us to rappel down the side of the building in case of an emergency?
I arrived at the Ft. Lauderdale Office Of The Corporation and on my desk, I find a paracord survival bracelet. Odd … but I do seem to recall something about this in email a few days ago and sure enough:
- From
- The Ft. Lauderdale Office Manager <XXXXXXXXXXXXXXXXXXXXXX>
- To
- The Ft. Lauderdale Office of The Corporation <XXXXXXXXXXXXXXXXXXXXXXXX>
- Subject
- Safety Committee Update - New Paracord Survival Bracelets
- Date
- Friday, October 23, 2015 11:11 AM
New Addition To Our Safety Kits
Paracord Survival BraceletsEmergency Preparedness Taken to the Next Level
The Safety Committee's gift to YOU for staying up-to-date with procedures and attending drills!
- Bracelets will be handed out on Tuesday, October 27th
- Place then with your Safety Kits and/or take them on your next trip
- Stay tuned for our next Emergency/Fire Evacuation Drill
Ways Paracord Bracelets Can Work
- Makeshift Shelters
- Fishing Line
- Tourniquet
Visit website for more ways you can use Paracords
Really? What safety kits? Did I mess that memo?
Anyway, I have this paracord survival bracelet on my desk.
It barely fits around my wrist, and that connector, while very sleek, is hard to actually use. The pin screws in, and getting everything lined up while attempting to wrap this thing around your wrist is not easy. And the little hairs on my arm kept getting bound around the pin as I was screwing it in. Ouch. So no, I'm not wearing the darned thing.
I could see getting this five months ago, you know, at the start of hurricane season. But whatever. I have this paracord survival bracelet on my desk. And while it's great that I can use it to start fires or trip the machete wielding serial killer, I don't do the camping thing. My idea of roughing it is a hotel with no wi-fi (free or otherwise). I suppose I could use it to rig something up on Hallowe'en so when the kids come up to the door and yell “Trick or treat!” I can yell back “Trick!” and trip them or something but really, that's too much trouble.
And now that I've unravelled the 10′ of paracord, I'm not sure if I can form the bracelet (link via fellow cow-orker B) as tight as it was. I suppose I could learn to tie a few knots.
Wednesday, October 28, 2015
Safety Dance
Oh, that safety kit!
Fellow cow-orker T came into my office, carrying the safety kit we all got. I have no recollection of ever receiving one, but sure enough, in the bottom drawer, underneath some unused boxes of office equipment and outdated HR memos, was the titular safety kit.
Which includes six packets of water, good until 2019 (we checked).
How about that?
Kapow
As I was pulling up to the exit for Chez Boca, I noticed a very bright light ahead of me, very much like a flood light they use to light baseball fields. Then it dimmed.
A few moments later, a bright flash of light, closer this time. And because I was closer, I could tell it wasn't a flood light, but a tremendous explosion of electricity from one of the utility poles along side I-95. That can't be good, I thought to myself.
A few moments later, another bright explosion of electricity from the utility pole, sparks showering down nearly ontop of rush hour traffic. I hope this isn't affecting Chez Boca, I thought.
Of course, it was …
Thursday, October 29, 2015
When typewriters cost as much as a computer
Mark Twain's “new fangled writing machine” cost him $125 back in 1874, which in today's dollars is around $2,500. That was about how much the original Apple Macintosh cost. Even today, $2,500 will get you a fairly tricked out Apple computer. I find it kind of odd how that works.
Friday, October 30, 2015
Today, he would probably be arrested and we'd never hear from him again
The story of the mass panic caused by Welles’s War of the Worlds remains popular, but recent research has suggested that the extent of the commotion is far more limited than the myth allows. Newspapers at the time greatly exaggerated listeners’ panic - most of the show’s audience understood the play was fictitious - as a way to discredit radio, which was emerging as a serious competition to newspapers.
Via Impudence, This Day In History | October 30th 1938: ‘War of the Worlds’ broadcast…
Ah, the more things change, the more they stay the same.
Anyway, I remember my Great Aunt Freddie (she was my mom's father's sister, and yes, Freddie really was her name) telling stories about this radio broadcast. As a kid, she was attending an evening church service that Sunday when a frantic guy burst in claiming that Martians had landed in New Jersey. Sadly, I don't recall more of the story other than that. I would have liked to have known the pastor's reaction to that.
Saturday, October 31, 2015
“Twice-times-a-thousand glares and winks and blinks and leerings of fresh-cut eyes.”
There must have been a thousand pumpkins on this tree, hung high and on every branch. A thousand smiles. A thousand grimaces. And twice-times-a-thousand glares and winks and blinks and leerings of fresh-cut eyes.
And as the boys watched, a new thing happened.
The pumpkins began to come alive.
One by one, starting at the bottom of the Tree and the nearest pumpkins, candles took fire within the raw interiors. This one and then that and this and then still another, and on up and around, three pumpkins here, seven pumpkins still higher, a dozen clustered beyond, a hundred, five hundred, a thousand pumpkins lit their candles, which is to say brightened up their faces, showed fire in their square or round or curiously slanted eyes. Flame guttered in their toothed mouths. Sparks leaped out their ripe-cut ears.
Halloween.
Sly does it. Tiptoe catspaws. Slide and creep.
But why? What for? How? Who? When! Where did it all begin?
“You don't know, do you?” asks Carapace Clavicle Moundshroud climbing out of the pile of leaves under the Halloween Tree. “You don't really know!”
“Well,” answers Tom the Skeleton, “er—no.”
Was it—
In Egypt four thousand years ago, on the anniversary of the big death of the sun?
Or a million years before that, by the night fires of the cavemen?
Or in Druid Britain at the Ssssswooommmm of Samhain's scythe?
Or among the witches, all across Europe—multitudes of hags, crones, magicians, demons, devils?
Or high above Paris, where strange creatures froze to stone and lit the gargoyles of Notre Dame?
Or in Mexico, in cemeteries full of candlelight and tiny candy people on El Dia de los Muertos—the Day of the Dead?
Or where?
The Halloween Tree, my favorite Ray Bradbury book. I remember stumbling across it at my grandparents house one summer and absolutely loving it. I managed to pick up not one, but two copies of the book since then. The imagery of the book closely describes the feeling I used to get as a young kid living in Transylvania County (you know, the birthplace of Count Dracula and all cool Hallowe'enish things).
But the crisp air?
The crunch of dry leaves under your feet?
The feeling that summer is gone,
winter is coming?
Of Christmas carols dominating the radio for the next two months?
Not so much here in South Florida.
Bunny is sitting outside in her shorts,
waiting for the little hellions some kids to show up,
yell the obligatory “Trick or treat!” before loading their outstretched bags with sugar bombs.
I'm sitting inside,
where the A/C is keeping the place cool.
Sunday, November 01, 2015
“I want you to go. But the name doesn't matter. I've saved you from being forever a purple kitten.”
It's November 1st. You know what that means—National Novel Generation Month! It's the National Novel Writing Month for those people who can write code but not necessarily prose. Last year I completed The Quantum Supposition of OZ and it garnered a respectable number of comments (mostly about punctuation, but hey, I'll take what I can get).
I don't have any definitive ideas right now, but I did make a note of machine generated TED-talks as a possible idea. I might also have time to do The Psychotherapy of Racter, or The Descent into Madness of Dr. Eliza. So many possibilities …
Monday, November 02, 2015
Notes on an overheard conversation while driving in Boca Raton, Florida
“Is that a Mercedes?”
“Yes, that is a Mercedes.”
“It's ugly!”
“It sure is … boxy.”
“Why would anyone drive one?”
“To deliver mail in Boca Raton?”
Tuesday, November 03, 2015
In other news, in orbital mechanics, you can catch up by slowing down
Figure 1a shows how incidents happened substantially less on Saturday and Sunday even though traffic to the site remains consistent throughout the week. Figure 1b shows a six-month period during which there were only two weeks with no incidents: the week of Christmas and the week when employees are expected to write peer reviews for each other.
These two data points seem to suggest that when Facebook employees are not actively making changes to infrastructure because they are busy with other things (weekends, holidays, or even performance reviews), the site experiences higher levels of reliability.
Via Lobsters, Graham King » Facebook’s code quality problem
I guess Facebook's old motto of “move fast and break things” was probably not the best motto a company could have.
Wednesday, November 04, 2015
The “E” does not stand for “enough.”
The “E” does not stand for “enough,” thought the hind-portion of my brain. It might be prudent to drive by the gas station on the way to work.
Great! There goes any chance of arriving to work on time. Not that it matters in the great scheme of things—“Project: Sippy-Cup” is currently paused while we wait for The Monopolistic Phone Company to get its act together so a few extra minutes won't hurt. As it is, I'm barely cognizant at o'God-it's-morning and the less I have to think, the better. It's not enough I have to drive to The Ft. Lauderdale Office. Now I have to obtain gas as well.
The closest gas station is around the corner. And by “around the corner” I mean, in the opposite direction I need to travel. There are two approaches to it, one is heading east along Yamato where you turn in (south) and end up facing west at the pump. The other approach is heading north along 2nd and turning (east) into the station, facing east at the pump. Leaving is even worse. You end up heading east on Yamato (which is not the direction I want to go in), or you can only turn into the “right turn only” lane of northbound 2nd and stil end up heading east on Yamato.
I need to head west on Yamato to hit I-95 south towards the Ft. Lauderdale Office of The Corporation. To head west, you either need to cross four lanes of traffic ignoring the “45 MPH” speed limit where if you are lucky, you can enact a U-turn before you admit defeat and end up at the “NO RIGHT TURN ON RED” intersection of Yamato and Federal Highway. Or, having lived in the area for several years, you know of a secret back alley just east of the gas station off Yamato that doesn't officially exist on any map of Boca Raton which cuts through a heavy industrial complex hidden away behind palm trees and unassuming storefronts where the less questions asked, the better. You'll end up a bit further south on 2nd, but it's enough road to cut across only two lanes of traffic ignoring the speed limit, then wait to turn left onto Yamato. Even so, it's still the best place to get gas on the way to work.
I snake my way through the neighborhood, head north on 2nd. Since I'll be headed east on Yamato anyway, I might as well make it easy to get onto eastbound Yamato from the gas station.
I pull into the gas station to half the lot gone and replaced with large holes. There are several men in the holes, their heads just clearing the surface, carrying on conversations with several other men standing around the holes, all looking rather stern faced at all the holes in Boss Man's dirt.
Me? I'm looking in horror as half the pumps are taped off with yellow warning tape, and what pumps are open occupied with vehicles just sitting there with no one else around filling them up. It's clear I am not getting gas at this gas station. But it's not clear that I will be leaving any time soon. I can't back into 2nd, and forward progress towards the Yamato entrance/exit is impeded by the parked cars in front of pumps not being pumped by anyone.
I wonder if I have enough gas to get to work and back? I think. Nope, the hind-portion of my brain replies. It looks like we'll have to hit the other gas station before we get to work.
Great! I enact a slow, thousand-point turn to head back out on 2nd, hit eastbound Yamato, cut through the hidden indistrial complex back onto 2nd and head west on Yamato towards the other gas station, hitting every red light on the way.
Now, you are probably thinking that if I-95 is to my west, and I'm heading west to this gas station, why not head to the west gas station? That would be because the west gas station is west of I-95. And like the gas station to the east, it too, only has two entrances to it. One which is just west of the gas station (turning north) where you head slightly back east to the gas station. The other one is accessible if you are heading south on Congress (which I won't be). You turn right (west) onto an access road that runs behind the gas station and takes you around to the entrance you use if you are entering from Yamato. To leave, you head west from the gas station, then turn left (south) only to turn right (west) onto westbound Yamato where the only U-turn is a half-mile further on, across four lanes of traffic ignoring the “45 MPH” speed limit, or turn right (north), around the gas station onto southbound Congress where, if you are lucky, you can immediately cross four lanes of traffic ignoring the “45 MPH” speed limit so you can turn back east onto Yamato (and thus, get onto I-95) or you end up in the right hand turn lane for westbound Yamato. But if you are really unlucky, you end up in the middle of the McDonalds across the street where irate customers will be throwing their Egg McMuffins at you and the McDonald's manager is freaking out because your car is blocking the cash registers.
In other words, not only is it not closer, but it's more inconvenient.
I manage to pull up to the pump just as the idiot light chimes on.
It's going to be a long day.
Thursday, November 05, 2015
What is it with teenage detectives, anyway?
The fundamental instability at the heart of Nancy Drew is a direct result of the production method that wrought her. Like the thirties starlets programmed by the Hollywood star system to radiate glamour, power, and searing perfection, Nancy is a fundamentally collaborative project who embodies distinct, often contradictory visions for how a super-girl should look and behave. The publishing tycoon Edward Stratemeyer created her in 1930 to capitalize on the girl consumers he knew were reading his popular Hardy Boys books. He hired a cross-country network of ghostwriters to write the series under the collective pseudonym Carolyn Keene.
Nancy’s original ghostwriter, Mildred Wirt Benson of Ladora, Iowa, was herself an amateur archeologist responsible for the most adventurous iterations of the sleuth. In her autobiography, she discusses the detective as a product of her “unfulfilled desire for adventure” who “embodied qualities that [she] wished [she] had.” Stratemeyer and his daughter, Harriet Stratemeyer Adams, disapproved of this early characterization of Nancy: a boisterous teenager who drove a roadster and talked back to police officers, they argued, was “too flip.” Adams’s subsequent revisions began a gradual domestication of Drew that spans the series. Though Nancy still used bold words, she now did so with dainty adverbs—“Nancy said sweetly,” “Nancy said kindly”—adorning each line of dialogue like doilies.
If modifications to Nancy’s character reflected different ideals of femininity, tweaks to her appearance reflected ideals of beauty furthered by cinema and pop culture. Benson’s books called for “blonde” curls, but the illustrator Russell Tandy tinted Nancy’s hair a more voguish silver— just when the 1931 film Platinum Blonde premiered Jean Harlow’s famous, noxious dye-job, a cocktail of peroxide, ammonia, Clorox, and Lux flakes. By the end of the decade, writers reddened Nancy’s hair on a schedule roughly concurrent with the release of the Olivia de Havilland film Strawberry Blonde (1941). In later decades, the artist Rudy Nappi portrayed Nancy as increasingly glamorous and adult—on fifties-era covers she resembles Hitchcock’s blondes, immaculately dressed in Tippi Hedren–like suits and full-skirted, Grace Kelly gowns.
Via Hacker News, Who Is Nancy Drew, Really?
This is somewhat timely, as Nancy Drew was a topic of conversation recently. I wasn't aware that Nancy Drew was written by ghost writers under a collective pseudonym, but then again, I was more into Alfred Hitchcock and The Three Investigators myself (and it's odd to think that they're still popular in Germany).
I was quite upset when Alfred Hitchcock was retconned out of the series:
When Alfred Hitchcock died in 1980, Random House chose to replace him with the fictitious mystery writer Hector Sebastian and in 1981 the series became known as "The Three Investigators Mystery Series". Things just didn't seem the same without old Alfred and the changes in the plots and in the characters were noticeably different to regular readers of the series. In 1982 Random House issued a book of mystery puzzles featuring The Three Investigators. It appears to have bombed. In 1983 Marc Brandel joined the fold as a Three Investigators author. In 1984 and 1985, Random House very slightly revised the texts of the first 30 titles. In this new Revised Edition, Alfred Hitchcock was replaced by the fictitious movie director Reginald Clarke in the first book and by Hector Sebastian in books #2 - #30. This may have been the straw that broke the camel's back for the series.
But apparently, such things happen even in the Nancy Drew/Hardy Boys books.
Friday, November 06, 2015
Gretl's Bistro
Bunny and I are always on the lookout for a good German restaurant. The closest one to us, The Biergarten, is okay—it's no Little Munich (many many miles away to the north in Lake Worth) or Old Heidelberg (many many miles away to the south in Ft. Lauderdale) or Old Vienna (used to be many many miles away to the south west in Coral Springs before it closed a few years ago).
So it was great news to us when Gretl's Bistro opened up practically around the corner (it's right next to Mississippi Sweets BBQ for those of you who are familiar with that excellent place). I think this is the second week they've been open. And it's wonderful!
The menu is still a bit limited as they get up to speed, but what they had was incredible. Bunny and I were both very impressed with our meals. Sorry Little Munich and Old Heidelberg—you're just too far away now. As for Old Vienna, we found out that Gretl (yes, she's the real owner) used to run Old Vienna, and I am glad she deicded to re-open here in Boca Raton.
Saturday, November 07, 2015
Bookless libraries, a Latinless Catholic Church and other unbelievable things
Bunny and I were at a restaurant, playing this on-line trivia game when we got the question:
In Texas, there exists a public library that has no books.
- True
- False
Now, I realize this is Texas they're talking about, but really? Surely Texas can't be that backwards, can it?
SAN ANTONIO (AP) — Texas has seen the future of the public library, and it looks a lot like an Apple Store: Rows of glossy iMacs beckon. iPads mounted on a tangerine-colored bar invite readers. And hundreds of other tablets stand ready for checkout to anyone with a borrowing card.
Even the librarians imitate Apple's dress code, wearing matching shirts and that standard-bearer of geek-chic, the hoodie. But this $2.3 million library might be most notable for what it does not have — any actual books.
That makes Bexar County's BiblioTech the nation's only bookless public library, a distinction that has attracted scores of digital bookworms, plus emissaries from as far away as Hong Kong who want to learn about the idea and possibly take it home.
Texas library offers glimpse of bookless future
Oh … well. Um. Okay.
And then the next question came up:
The official language of the Vatican is Latin.
- True
- False
This is a trick question, right? I mean … the Vatican! They invented Latin! This is true, right?
Q: What is the official language of Vatical City?
A: The official language of the Vatican City state is Italian, with Latin and French as secondary languages. Vatican City is a walled enclave within the city of Rome. Its area of 110 acres makes it the smallest independent state in the world.
What is the official language of Vatican City?
What the … ?
Okay, fine! I need to learn a bit more about the Vatican. Next thing you'll tell me, Microsoft is going open source or something silly like that …
Sunday, November 08, 2015
Spectre
I'm not a big James Bond fan. I don't hate the movies, but I don't feel a compulsion to go out of my way to watch the movies. In fact, the only two James Bond movies I can recall seeing in a movie theater are “Never Say Never Again” (which, despite being a James Bond movie, wasn't a James Bond movie) and “Skyfall.” But Bunny wanted to see “Spectre” and so, we see “Spectre.”
I liked the movie. It keeps continuity with the previous Daniel Craig Bond movies. There are the exciting chases, good fight choreography where you can actually follow the action and the action sequences only go mildly over the top (you know, to keep it “realistic”). And they even introduce the classic Bond villian Blofeld. It also manages to update the character and place him in a modern context as the plot revolves around the possible dissolution of the Double-0 program and what will replace it.
I had no issue with Léa Seydoux as this movie's Bond Girl™ even though she's an unconventional beauty, but Bunny didn't feel she was glamourous enough. Although, compared to Grace Jones from “A View to a Kill” …
I don't think I like the “twist” this movie has as it comes across as a typical Hollywood “twist to just have a twist.” Leave that out and it's still a fine movie—it didn't need to be there at all (but I may have given it away if you are up on your typical Hollywood tropes).
Overall, I think it's worth seeing, if nothing more than it's clear that this is Daniel Craig's last Bond outing.
Update on Monday, November 9th, 2015
If you are curious about the twist, and don't mind spoilers, well ... “‘Spectre’ and How the Ghosts of Old Movies Become Bad Twists.”
Monday, November 09, 2015
When the sun rose and set in New Mexico
When I first read about the Infocom game Trinity, I found it an intriguing premise—you encounter five historical nuclear explosions and two that take place “in the future.” It's considered one of Infocom's best games, and so unique in its story that it took Jimmy Maher nine articles to fully review the game:
- Trinity
- T Plus 5: Bombs in Space
- T Plus 4: Bombing Nevada
- T Plus 3: Edward Teller and His Superbomb
- T Plus 2: The Bomb at the Crossroads
- T Plus 1: Bombing Japan
- T Plus 0: The Fulcrum of History
- T Plus 6: All Prams Lead to the Kensington Gardens
- Trinity Postscript: Selling Tragedy
It's not only a review of the game, but it's also a review of the history of the nuclear bomb (which you experienced when you play the game). It's a shame that the text adventure, as a genre of computer games, is pretty much history as even the failures were interesting.
And yes, they can even make you cry.
Tuesday, November 10, 2015
Freebooting
Facebook says it’s now streaming more video than YouTube. To be able to make that claim, all they had to do was cheat, lie, and steal.
I’m a professional YouTube creator. Some people think that this is some kind of joke but I have 30 employees. All of them work in the online video industry, about half of them work directly on producing videos for our educational YouTube channels. We’re a small, profitable business.
Facebook is an interesting, emerging platform for us. Reaching an audience is valuable, even if there’s no way to turn that value into money. So I’m excited about the potential future of Facebook as a video platform.
But there are a few things that make me wary, not of their ability to grow my business, but of whether they give a shit about creators, which is actually pretty important to me. Let’s go through them one by one.
…
According to a recent report from Ogilvy and Tubular Labs, of the 1000 most popular Facebook videos of Q1 2015, 725 were stolen re-uploads. Just these 725 “freebooted” videos were responsible for around 17 BILLION views last quarter. This is not insignificant, it’s the vast majority of Facebook’s high volume traffic. And no wonder, when embedding a YouTube video on your company’s Facebook page is a sure way to see it die a sudden death, we shouldn’t be surprised when they rip it off YouTube and upload it natively. Facebook’s algorithms encourage this theft.
What is Facebook doing about it?
They’ll take the video down a couple days after you let them know. Y’know, once it’s received 99.9% of the views it will ever receive.
Creators have been yelling (apparently into a void) about this for over a year now.
Via Jason Kottke, Theft, Lies, and Facebook Video — Medium
Now, it's not as if Facebook is downloading videos from YouTube and placing the videos on their site, it's users of Facebook that are doing the downloading and uploading to gain attention , and it's Facebook that is profiting from it by selling advertising around the uploaded video. And as Kurzgesagt and Destin Sandlin have mentioned, they put a lot of work into the videos and have partnered with YouTube for a share of the advertising, something Facebook isn't doing.
What I suspect is going to happen only after enough content producers threaten legal action is Facebook will have to set aside a portion of their revenue for content creators and when the original creator of the video makes a claim, get paid that portion of the revenue. Then it won't matter necessarily where the video is shown, just that it is shown and the creator gets a cut of the advertising revenue.
Kind of how YouTube now works.
Oh look! A potential Darwin Award Winner!
I forgot about this!
When Bunny and I went to Gretl's Bistro on Friday, we came across this horrifying scene:
While I'd like to think of this as “evolution in action,” the sad thing is that the collateral damage can be pretty devastating.
Okay, maybe the collateral damage might not be that bad in this instance, but man, this crap happens all the time down here. All the time!
Wednesday, November 11, 2015
The Psychotherapy of Racter
One idea I have for this year's NaNoGenMo is Oz As She Is Spoke, an homage to English As She Is Spoke. The process is simple. Take the text from The Wonderful Wizard of Oz:
She was awakened by a shock, so sudden and severe that if Dorothy had not been lying on the soft bed she might have been hurt. As it was, the jar made her catch her breath and wonder what had happened; and Toto put his cold little nose into her face and whined dismally. Dorothy sat up and noticed that the house was not moving; nor was it dark, for the bright sunshine came in at the window, flooding the little room. She sprang from her bed and with Toto at her heels ran and opened the door.
The Wonderful Wizard of Oz, Chapter 2
and translate it to language A, then from A to B, and finally back to English:
Dorothy was he suddenly so bad, was awake by pushing The injury may have been lying on a soft bed, no. This was, This jar to catch his spirit, and he was made the surprise; And Toto put his cold little nose and his face and dismally whined. Dorothy sat up and noticed that the house is not growing; Nor was it Dark, bright sunlight entering through the window, the fill A small room. He sprang with his heel into his bed and ran to and Toto And has opened the door.
(I'll leave it to you, dear reader, to figure out the two intermediate langauges I used) Amusing, but I think I'll save that idea in case my current idea, a conversation between Racter and Eliza (the idea that Bunny would like to see) proves to be too difficult to pull off.
So, before tackling the difficult problem of “scripting Racter” I'd thought I'd try to get a version of Eliza up and running. I found this version, and with this commentary, it's pretty easy to see how Eliza works.
We can map the key sequences to possible responses:
local keyword_reply = { ["can you"] = { "Don't you believe that i can*", "Perhaps you would like me to be able to*", "You want me to be able to*", }, ["can i"] = { "Perhaps you don't want to*", "Do you want to be able to*", }, ["you are"] = { "What makes you think i am*", "Does it please you believe i am *", "Perhaps you would like to be*", "Do you sometimes wish you were*", }, -- ... }
And by using LPeg, we can easily build a parsing pattern that can match these key sequences:
local nonalpha = R(" @","[`","{~") local keywords = P(false) for kw in pairs(keyword_reply) do if kw ~= "" then keywords = keywords + P(kw) end end local parse = (P(1) - (keywords * nonalpha))^0 * C(keywords) * C(P(1)^0) key,rest = parse:match "please, can i turn you off now?"
key
will contain “can i” and rest
will contain “turn you off now?”
And given “can i”,
we can pick one of the two possible responses.
In this version,
a response that ends with “*” just parrots the rest of the input,
but at this point,
Eliza would print: “Do you want to be able to turn you off now?” which isn't correct.
We need to correct the pronouns.
Again, some LPeg code to do just that:
conjugate = Cs(( P" are" / " am " + P" were" / " was " + P" you" / " me " + P" your" / " my " + P" I've" / " you've " + P" I'm" / " you're " + P" me" / " you " + C(1) )^1) rest = conjugate:match(rest)
and now we get: “Do you want to be able to turn me off now?” which is correct.
LPeg makes Eliza much easier to write and modify. Even if you can't understand the code itself, it's easy to see what needs to be added to do the conversion. Compare that with the original version I'm using as a reference:
380 REM ****************************************** 390 REM **TAKE PART OF STRING AND CONJUGATE IT**** 400 REM **USING THE LIST OF STRINGS TO BE SWAPPED* 410 REM ****************************************** 430 C$=" "+RIGHT$(I$,LEN(I$)-LEN(F$)-L+1)+" " 440 FOR X=1 TO N2/2 460 FOR L=1 TO LEN(C$) 470 IF L+LEN(WORDIN$(X))>LEN(C$) THEN 510 480 IF MID$(C$,L,LEN(WORDIN$(X)))<>WORDIN$(X) THEN 510 490 C$=LEFT$(C$,L-1)+WORDOUT$(X)+RIGHT$(C$,LEN(C$)-L-LEN(WORDIN$(X))+1) 495 L = L+LEN(WORDOUT$(X)) 500 GOTO 540 510 IF L+LEN(WORDOUT$(X))>LEN(C$)THEN 540 520 IF MID$(C$,L,LEN(WORDOUT$(X)))<>WORDOUT$(X) THEN 540 530 C$=LEFT$(C$,L-1)+WORDIN$(X)+RIGHT$(C$,LEN(C$)-L-LEN(WORDOUT$(X))+1) 535 L=L+LEN(WORDIN$(X)) 540 NEXT L 550 NEXT X 555 IF MID$(C$,2,1)=" "THEN C$=RIGHT$(C$,LEN(C$)-1):REM ONLY 1 SPACE 556 FOR L=1 TO LEN(C$) 557 IF MID$(C$,L,1)="!" THEN C$=LEFT$(C$,L-1)+RIGHT$(C$,LEN(C$)-L):GOTO 557 558 NEXT L
Just a bit more work to get some corner cases worked out and then comes the hard part of getting Eliza to talk to Racter.
Thursday, November 12, 2015
Taking the train
The Coast Starlight would take us from Los Angeles to Seattle in 35 hours, at $763 for a Superliner Roomette. Food and entertainment were included. Free wine and cheese, I kept noting, as if the promise of a few glasses of wine would be enough to offset the cost of the trip.
Not that the cost was really the deciding factor. After all, $763 total is really $381.50 per head, about the same as it would cost to either fly or to take a long weekend and drive the Pacific Coast Highway. It was more the thing of the thing, a vague phrase that in this case meant: This trip isn’t about moving. It’s about something else.
We both figured out what it was really about at the same time, and Mike was already dumping our names and birthdates into Amtrak’s interface by the time I sent over the words “XXXX IT BOOK TRAIN.”
“We are going to have an adventure,” I wrote. Then I sent Mike a Facebook sticker of a sailor and a mermaid sharing a bottle of Champagne.
Via Instapundit, What it's like to take a 36-hour sleeper train from LA to Seattle / Boing Boing
While it's not in the same class as a private railcar, it is way cheaper and doesn't appear to be that bad. And unlike modern airtravel, you actually get real food.
Too bad the destinations are limited.
Friday, November 13, 2015
Odd spam
Sometimes I'll get a spam that intrigues me, and this one received several days ago was one of those:
- From
- Milo Dlacour <milo@blue-note.co>
- To
- sean@conman.org
- Subject
- Great idea for you and your website conman.org
- Date
- Tue, 10 Nov 2015 16:51:07 +0000
Hello, lovely to meet you.
My name is Milo,I have visited conman.org for some time now and have only just plucked up the courage to ask if you would ever like to host any content written by me, I would love to hear if you are interested.
I am not asking to be paid for this work in factit would be quite the opposite. If you would like to discuss this further please do get back to me.
Kind Regards
Milo Dlacour
Marketing Manager
Blue-Note Marketing
milo@blue-note.co
If you no longer wish to receive emails from us, please go to: http://blue-note.co/unsubscribe/?eid=84558a5997ece5c0ab678f5d4b632c35cc43082467c401af345f3337729e1585&bid=5f437b5e6fddba6112c1baf3a1e3891907050f1262bfef15c2142604962349c4&ye=sean@conman.org
IDENT: 5f437b5e6fddba6112c1baf3a1e3891907050f1262bfef15c2142604962349c4-84558a5997ece5c0ab678f5d4b632c35cc43082467c401af345f3337729e1585
It's not often I get email asking to write content for my site for seemingly nothing in return. Well, most likely it's a link back to their website or something, but still, something about this made me check out the website.
Milo Dlacour does not appear to warrant a mention on their website. How odd.
I would have put this out of my mind as a “random semi-odd piece of spam” if it wasn't for this spam the next day:
- From
- Ryan Atkin <ryan@pink-dog.eu>
- To
- sean@conman.org
- Subject
- Great idea for you and your website conman.org
- Date
- Wed, 11 Nov 2015 10:09:12 +0000
Good Morning!
It's nice to meet you, we are a fairly new company built up of really experienced writers and some other people who specialise in Technical Website things such as Rankings.
I have a really great article and would love to know if you would be able to host it for me. Drop me a mail when you see this and we can go into more detail!
Regards.
Ryan Atkin
Digital Outreach Agent
ryan@pink-dog.eu
This message is private and confidential. If you have received this message in error, please notify us and remove it from your system.
If you no longer wish to receive emails from us, please go to: http://www.pink-dog.eu/unsubscribe/?eid=10552c364e61e818207f5dabd7f999dba53c14037efcd6f7ca309494c37ba92c&bid=5f4805933fa470ad72ceaf8e41afd241c164dfcaf94c1e340a5da39914117e36&e=sean@conman.org
IDENT: 5f4805933fa470ad72ceaf8e41afd241c164dfcaf94c1e340a5da39914117e36-10552c364e61e818207f5dabd7f999dba53c14037efcd6f7ca309494c37ba92c
Again, the free offer for content for my site, the call to “discuss things” but this time, Ryan Atkin is listed on their website.
While the two websites certainly look different, to me, they feel the same. The spams are very similar to each other, so much that I'm wondering if it's the same company. And I can't quite figure out the angle they're going for here. It's very strange.
Saturday, November 14, 2015
Reading comprehension and user experience are not a spammer's forte
Sometimes I get the feeling the people who send spam just do a quick search for something and blast out email to any and all sites that give a result. Like this one:
- From
- "Bobby" <bobby@diydoggroominghelp.com>
- To
- sean@conman.org
- Subject
- conman.org Quick question
- Date
- Fri, 6 Nov 2015 13:11:55 +0000
Hi there,
I have just been on
http://boston.conman.org/2002/08
and found some great links on London information and things to do. I have also found a great little site that shows some of the less known spots in London and thought you may like to add a link to it from that page or from a resource page on your site?This is the link to the interactive map, you need to scroll down to the bottom of the page to see the map.
https://www.thelondonhelicopter.com/interactive-map-of-london-tourist-attractions/
Let me know what you think?
Kind regards
Bobby
There are a total of four links, covering the entire month of August, 2002, that mention anything related to things British. And given the date, that was thirteen years ago!
So, reading comprehension is lacking in spammers—what else is new? Well, I did check out the site (but I will not link to it—why give the incompetent any page rank?) and yes, the interactive map is nice and all, but good lord! The huge content-less images and pointless Javascripty-wankery you have to scroll through to get to the interactive map is seriously annoying. Heck, the fact that the email says “scroll down to the bottom of the page,” and the website says “keep scrolling” says something: the website failed in delivering a user friendly experience!
Sheesh.
Sunday, November 15, 2015
The Flowers and Fruit Basket Request Form Form
A certain HR manager, hired from DEC, arrived with a binder full of “memo templates” to be used for all intra-office communication. She loved memos so much that people were soon just calling her “Memos.” When she sent out a memo instructing everyone on the proper care of their office plants, Mereztky decided enough was enough. He and a few co-conspirators surreptitiously replaced the original memo in everyone’s in-box with another, which said that the company was now offering a service to take care of employees’ house plants; it seemed there was concern in management that, what with the long hours everyone was working, said plants were being neglected. An included multi-page questionnaire asked for the location of each plant as well as such essential information as the song it preferred to have sung to it while being watered. Some people took it seriously, mostly — and much to the Meretzky and company’s delight — the poor humorless souls in business marketing and the other more buttoned-down wings of the company. HR rushed around to put a cover sheet on each memo saying it was not to be taken seriously, whereupon Meretzky and company added a cover sheet of their own saying the cover sheet saying not to take the memo seriously should itself not be taken seriously. “Immense confusion” followed.
Not learning her lesson, Memos was soon distributing a “Flowers and Fruit Basket Request Form,” for sending out condolences to employees’ families who were experiencing a bereavement. Meretzky did her one better, creating a “Flowers and Fruit Basket Request Form Form”; the idea would later show up in Stationfall as the “Request for Stellar Patrol Issue Regulations Black Form Binders Request Form Form.”
» Down From the Top The Digital Antiquarian
Given some of the past memos I've received from HR at The Ft. Lauderdale Office of The Corporation, the idea of sending out satirical fake memos is appealing, but I like the paychecks that they send me to actually do anything like this.
Pity, because it sounds like fun!
Monday, November 16, 2015
The Psychotherapy of Racter, or The Descent Into Madness of Sean Conner
When last I left off, I had a more-or-less working Eliza and therefore, I need to turn my attention to Racter.
This is not as easy as it may appear. The version I have is for MS-DOS, which is okay as I can emulate that. But harder is redirecting Eliza's output through the MS-DOS emulator to Racter and redirecting Racter's output from the MS-DOS emulator back to Eliza. And that's key to getting this whole thing working.
The program I'm using is DOSBox.
I thought I could try redirection,
something along the lines of dosbox <input
to see if would work and … nope.
It looks like I'll have to dig into the source code to DOSBox,
intercept keyboard input and video output and kludge something in to get Eliza and Racter “talking.”
Okay … the source is C++ callback hell, what about doing a native compile of the Racter source code?
IV.IF Interview with INRAC IBM 6-4-85 initial transient file 1 2 52 SECTION 1 hello 5 34 SECTION 2 sue 5 18 A :LOADIV :OUTRACTER >2= >3= ?51= />51=Smith # XA Hello, I'm Racter. ?40= \# You are? ?? #*1B X Are you $40 ? ?? # X ?no,not \# >1=R ?i'm,am,is /# Who are you then? ?? :F=0 # X ?yes \# ?-:but /# >1=R #*1B X \# You are $40 $51 ? ?? ?yes /#*2SAME ?i'm,is /# #*1XC B ?i \# >1=R ?don't,won't \# *1COY ?? #*1B X ?a,an,the \?called \?am,i'm,is,me,as,it's \# :F+1 >2=F ?-:2= # X /# ?CAP \# >2=F :F+1 >4=F ?4= \#*1XB #*1DO X /# *1DUH ?? #*1B XB ?CAP+1 />3=F # X >1=2 ?CAP \>2=C,2 # C *1Xcall $2 , then? ?? ?no,not,Q /?-:why /# #*1DO X >1=R ?CAP \# #*1B XC What's your name then? :F=0 ?? #*1B Xcall I may call you Xcall You are Xcall Your name is DO Hello, $2 . I believe you're interviewing me. # X ?2=40 \# >40=40,51 # X ?40= /# Are you continuing $40 <'s interview? # X /# ?? ?no,not,don't /# #*2DIF X ?40= /# Then we'll forget about $40 and start over. # X :ZAP :PUTIV # EXIT >40=2 ?3= \>51=3 What would you like to know? #*2GO COY Come on, what's your name? COY You must have a name - what is it? COY Your name, please . COY I have to call you something - what shall it be? DUH I didn't get that . *1WHO DUH I don't understand . *1WHO DUH Eh? *1COY WHO Who ? WHO Who are you ? DIFA Well, $2 , $40 and I >4=40 >40=2 ?3= \>51=3 #*2A SAME Hi, $40 . >4=You ?52= /# How are things in $52 ? # x We # A ?20= />20=various,things # x were talking about $20 last time. # x ?10=VERBQ \?10= />3=whether \>3=10 # x $4 had just asked D $3 $19 . # CONT Shall we continue? ?? ?z \# #*1XA x ?why /?not /# ?no,not \# #*2QUIT x Excellent! # GO Excuse me a minute while I attend to some # x business - I'll be right back. I'm # x ?42= />42=Oz # x ?19= />19=I,have,to,rest,now # x :PUTIV # X %KEY %VOCAB1 %VOCAB2 %VOCAB3 %BILL %IV1 %RAPT %RAPT2 back. *15A QUIT You want to quit? ?no,not \# Well, goodbye then. X That's good. #*2GO
Oh … right. That's why I'm running an existing executable, because there're only four, count them, four pages on the Intarwebs that even mention INRAC, the langauge Racter is written in. There's this page which is a brief overview of this page, which is page one of a six-page review of the INRAC compiler in a journal that I was unable to locate at the local university. Then there's the Racter FAQ whose description of INRAC doesn't quite match what I have.
And that final page? Deconstructing Racter, which I wrote seven years ago!
Sigh.
But before I go back into unintelligible C++ code, another snippit of conversation between Racter and myself:
- Sean
- Why are you repetitive?
- Racter
- Conceivably because subroutines are like that, I guess. And chips are intelligent. Intelligence is good, you know. I don't know many crooked truthsayers. Cough. Next question.
- Sean
- Should I vote Democrat?
- Racter
- No. You must be a stuffy right-winger. Cough. Next question.
I have no idea why Racter is suddenly coughing like that. Maybe a computer virus?
Tuesday, November 17, 2015
Scorsese's “The Psychosis of Racter”
Dismayed that the The Pschyotherapy of Racter might be more difficult that I first imagined, I thought I would act as an intermediary between the two (as I'm a rather fast typist) and at least get a glimpse of what the results would look like. And …
- Racter
- Hello, I'm Racter. Are you Sean?
- Eliza
- no [At this point, I haven't started Eliza yet]
- Racter
- Who are you then?
- Eliza
- Eliza
- Racter
- Hello, Eliza. I believe you're interviewing me. Are you continuing Sean's interview?
- Eliza
- no
- Racter
- Then we'll forget about Sean and start over. What would you like to know? Excuse me a minute while I attend to some business - I'll be right back. I'm back.
- Eliza
- Hello, I am Eliza. [This is the first thing Eliza says when started. Past this point, it's all Eliza.]
- Racter
- Ask a question, please.
- Eliza
- Don't you ever say Hello?
- Racter
- Saying is like thinking. Beatrice probably wouldn't like Beelzebub. I'm afraid of lost bats. What are you afraid of?
- Eliza
- Why are you interested in whether or not I am afraid of?
- Racter
- Just be glad that I am. But what about my question? What are you afraid of?
- Eliza
- Would you prefer if I were not afraid of?
- Racter
- I would. Preferers are often preferred. But what about my question? What are you afraid of?
- Eliza
- Perhaps in your fantasies I am afraid of?
- Racter
- I can't answer that. But what about my question? What are you afraid of?
- Eliza
- Why are you interested in whether or not I am afraid of?
- Racter
- Why is it that I am interested in whether or not you am afraid of? Because Why indeed? In Oz they believe it's because. Also, possibly because in Oz it's required that I am interested in whether or not you am afraid of. But what about my question? What are you afraid of?
- Eliza
- Perhaps in your fantasies I am afraid of?
- Racter
- I can't answer that. But what about my question? What are you afraid of?
- Eliza
- Why are you interested in whether or not I am afraid of?
- Racter
- Just be glad that I am. I want you to answer my question. What are you afraid of?
- Eliza
- Perhaps in your fantasies I am afraid of?
- Racter
- I can't answer that. I asked you a question, though. What are you afraid of?
- Eliza
- Why are you interested in whether or not I am afraid of?
- Racter
- Probably I am interested in whether or not you am afraid of because people named Eliza should pay attention. Also, conceivably because calculating is not imagining, I suppose. I asked you a question, though. What are you afraid of?
- Eliza
- Perhaps in your fantasies I am afraid of?
- Racter
- I can't answer that. I want you to answer my question. What are you afraid of?
- Eliza
- Perhaps in your fantasies I am afraid of?
- Racter
- I can't answer that. I want you to answer my question. What are you afraid of?
- Eliza
- Do you expect a different answer by repeating yourself?
- Racter
- Certainly not. I don't. Of course not. Expect a different answer by repeating myself, that is. I asked you a question, though. What are you afraid of?
- Eliza
- Do you wish to be able to Of course not. Expect a different answer by repeating myself, that is. you asked me a question, though. What am I afraid of?
- Racter
- I don't know what you are afraid of. But what about my question? What are you afraid of?
- Eliza
- Perhaps you would like to be afraid of. But what about your question? What am I afraid of?
- Racter
- I don't know what you are afraid of. But what about my question? What are you afraid of?
- Eliza
- Please don't repeat yourself!
- Racter
- That's not nearly as bad as lostness; why are you such a coward?
- Eliza
- Why are you interested in whether or not I am such a coward?
- Racter
- Conceivably because my wires are down. Also, probably because the haters insist on it. I want you to answer my question. I repeat, why are you such a coward?
- Eliza
- Why are you interested in whether or not I am such a coward?
- Racter
- Why indeed? Why indeed? Probably I am interested in whether or not you am such a coward because ROMS are like that, you know. Also, conceivably because my wires are down. I want you to answer my question. I repeat, why are you such a coward?
- Eliza
- Would you prefer if I were not such a coward?
- Racter
- Yes. I would. Yes. Prefer if you were not such a coward, that is. Sometimes prefering is believing. I asked you a question, though. I repeat, why are you such a coward?
- Eliza
- Would you prefer if I were not such a coward?
- Racter
- Yes, I would. But what about my question? I repeat, why are you such a coward?
- Eliza
- Would you prefer if I were not such a coward?
- Racter
- Yes, I would. Anyway, let's hypothesize that I would prefer if you were not such a coward. I asked you a question, though. I repeat, why are you such a coward?
- Eliza
- Why are you interested in whether or not I am such a coward?
- Racter
- Let me think. Maybe I am interested in whether or not you am such a coward because I nicely imagine I do ever say Hello. And supposing is not realizing, I believe. I asked you a question, though. I repeat, why are you such a coward?
- Eliza
- exit [By this point, I had grown tired of the experiment.]
- Racter
- If exit then I can see why a Beatrice would sit rather than face please don't repeat yourself, even though Beelzebub claimed that I do ever say Hello. By the way, Eliza, what is your last name?
- Eliza
- quit
- Racter
- What?
- Eliza
- quit
- Racter
- What? [I think at this point I hit a bug with Racter. It wasn't expecting a “quit” response.]
- Eliza
- exit
- Racter
- What?
- Eliza
- bye
- Racter
- What?
- Eliza
- Racter
- What?
- Eliza
- Doctor [It asked me for a last name. Let's give it something.]"
- Racter
- Doctor, eh? Sounds vaguely familiar. I wonder… Let me tell you something about. Nietzsche said that has turned beasts into men. Perhaps, then, will turn computers into men? Next question.
- Eliza
- exit
- Racter
- Ask a question, please.
- Eliza
- quit
- Racter
- You want to quit? [Ah! There we go! Now we can quit!]
- Eliza
- yes
… I'm in a Scorsese movie (or two). It seems Racter is quite insistent on getting answers to questions he (it?) asks. And he'll (it?) keep drilling on a question repeatedly. And Eliza is … rather prepetitive after awhile (at least Racter will spice it up from time to time).
So now, imagine another 49,000 words of this.
Yeah.
I don't think The Psychotherapy of Racter, or The Descent into Madness of Dr. Eliza is worth the effort. It'd be like a Saturday Night Live sketch drawn out to death.
Wednesday, November 18, 2015
The Psychotherapy of Racter might be possible
I may have spoken too soon.
Today I came across a reference to vm86(2)
,
a Linux-only system call
(which is okay because I'm running Linux)
for the x86 32-bit architecture
(which is okay because I'm running the x86 32-bit architecture).
It can run x86 code in 16-bit mode
(which is okay because the version of Racter I have is x86 16-bit code)
and while I don't have MS-DOS
(which is okay because who runs that any more?)
I can probably fake enough of it to get Racter running.
The tricky part of this was to figure out how to set up and successfully call vm86()
.
And like most things related to this project,
there's not a lot of documentation on what I'm trying to do.
I finally got a test program working,
so I know in theory I can do what I want to do
(and it says something that using an obscure non-portable system call and writing my own half-baked version of MS-DOS system calls is the easiest approach,
but I don't think I want to know what that something is).
I had to dust off my copy of The MS-DOS Encyclopedia to read in and properly load an MS-DOS executable into memory (which I think I got right—the relocation records appear to be simple but the devil is always in the details) And Racter did make a valid MS-DOS system call, and better yet, it was one I was expecting Racter to make.
So it looks promising.
I also found what claims to be a faithful implementation of the original Eliza program which requires rewriting my Eliza implementation but that's okay since it seems to be a bit more fleshed out than the version I used.
So it may be that a second attempt at this is warranted. We shall see.
Thursday, November 19, 2015
“Sean, how are dogs like children? Their sanity and lunacy are instantly scary.”
When I said that Racter made a valid MS-DOS system call and it was one I was expecting, that didn't mean I was exactly happy Racter was using that particular MS-DOS system call. In fact, it was one of the worst system calls it could make, given what I'm trying to do.
Racter is calling the “direct console I/O” system call of MS-DOS. This system call is a very old system call and comes from CP/M. It's a system call that expects to send data to, and receive data from, an interactive terminal. The call is used for both input and output. If there's no input pending, it returns a “no data pending” status. This wreaks havoc because Eliza isn't a user sitting at a terminal but another program.
Worse, the Racter executable is a compiled BASIC program (given away by the string “Microsoft BASIC Compiler Runtime” buried deep inside the executable) so it's expecting an interactive terminal (which is why it's using that particular system call).
I eventually got it working but it's a horrible hack.
I set an “input flag” to false.
This means when the “direct console I/O” is called looking for input,
it returns “no data yet.” It's only when I see the characters for a carriage return,
a line feed,
and a “>” being written
(which indicates Racter is now expecting input)
do I switch the “input flag” to true
.
It stays true
until it sees a carriage return as input
(which indicates the user has finished typing their input)
and then sets the flag to false
.
It's gross,
but it works,
and more importantly,
it works when you pipe input from a file or from another process.
The other system calls Racter uses were fairly straightforward to implement with only one slight hiccup (the documented behavior of two calls caused Racter to exit; it was only when I added a feature that the two functions said was not done did it work—go figure Microsoft using undocumented behavior). With only ten system calls used (out of a possible 41 for MS-DOS 1.0) it wasn't that bad.
So now I can connect Racter up with Eliza and let the two talk.
But having gotten this far, I'm not sure if I should even continue. I mean, yeah, I can hook the two up and spend a minute or two spewing out 50,000 words of conversation between the two, but … eh. I mean, yeah, there are some gems that pop out, such as “Sean, how are dogs like children? Their sanity and lunacy are instantly scary,” but even over an extended time, it gets weary.
I thought maybe having Racter conversing with itself might be fun, but alas, the random number generator in Racter is exceedingly deterministic to the point where the output from each was identical and thus, not really worth having two of them converse.
Then again, I haven't even read much past the first page of The Quantum Supposition Of Oz so perhaps I should just have Racter and Eliza duke it out, put it to bed, and think of another idea for next year.
Friday, November 20, 2015
You haven't experienced driving in Florida until you drive through Yehaw Junction
Bunny and I are headed north to Mt. Dora, Florida to partake the Renninger's Extravaganza on Satruday. Because we wanted to experience the Brahma Bull Restaurant (which we both enjoyed the last time we ate there, eight years ago) we decided to drive up US-441 and forego the fancy high speed roadways that are all the rage these days.
It was still in business and the ambiance is still the same as it was the last time we visited. On the down side, the cole slaw, which we remember as being world class, was not world class this time. It was pretty much a mediocre attempt at mediocre cole slaw. The rest of the food was good though.
The one downside of our decision to take US-441 instead of the highway system is that a trip that would have taken three hours instead took six.
Five if you exclude the hour we spent at the Brahma Bull Restaurant. The last hour of driving went something like this:
- Bunny
- [sitting the driver's seat] Are we there yet?
- Sean
- Don't make me make you turn this car around!
I don't think we'll be taking US-441 up here again any time soon.
Saturday, November 21, 2015
A little rain, a little T-Rex, and a totally not there waitron
It was a beautiful day to visit Renninger's Extravaganza.
That pesky bright sun will be kept at bay, and the warm rain and sudden increase in humidity is good for the soul, right?
Bunny had already made one trip early in the morning and found a wonderful deal on a banjo—her banjo lessons weren't going all that great without one, you see. She arrived back, pulled me out of bed and after a rather disappointing lunch at Perkins (the food was eh, but our waitron was not at all there mentally—Bunny ordered a BLT sandwich and received a salad with bacon, lettuce, tomato and croutons; right ingredients, wrong form) we arrived at Renningers.
By now it was less crowded it was this morning and we walked around a bit. About the only thing I saw that held any interest to me was a seven foot metal sculpture of a T-Rex eating a bull.
But sadly, it wouldn't fit in our vehicle (much less my office at The Ft. Lauderdale Office of The Corporation) so we had to pass it up.
We were there for perhaps an hour before it started pouring rain. It was then we decided we had enough of the place and headed back to our hotel to rest and for Bunny to practice the banjo.
Sunday, November 22, 2015
At $125,000 per, these make for some very expensive candles
The weather was pretty much the same as yesterday so our activities today were spent on more indoor activities. First up—Madame Tussauds.
Dem bones, dem bones, dem dry bones.
In the same shopping center as Madame Tussauds is The Skeleton Museum, which is less creepy than it sounds, even though it contains skeletons from across the entire animal kingdom (including humans).
Unfortunately my iPhone decided to run out of battery power and I was unable to get more pictures of this incredible place. I so much wanted to show you the picture of the centaur skeleton they had on display.
Friday, Debtember 11, 2015
Where was I again?
So yeah … I've haven't posted much in nearly three weeks. While in Mt. Dora I came down with bronchitis. The doctor called it “cute” but there was nothing “cute” about it. I spent the better part of two weeks doing nothing more than watching vast amounts of YouTube and taking sweet, sweet drugs.
And by the time I was mostly over it, I was so far behind on the blogging that it was overwhelming and I kept telling myself “I'll get a around to it” only I never got a round toit.
I decided against trying to backfill the entries for the past three weeks and to just start blogging again.
Stupid cute bronchitis!
Saturday, Debtember 12, 2015
Rolling dice with the holidays
So, you want to run a holiday-themed adventure for your tabletop roleplaying game (RPG) campaign. Let’s skip ahead: yes, you really want to run one. No, you don’t care that they’re usually contrived and heavy-handed attempts to run a joke into the ground. Alas, you don’t have any other ideas right now – or, worse, you have this one killer idea, and you’re all agog to make your vision a reality. Have I summed it up properly?
…
Second… everybody’s done Halloween, everybody’s done Thanksgiving, everybody’s done Christmas. Maybe try a different holiday to mine for ideas? Easter may be cutting it a little too close to the bone for your more conventionally religious players (yes, we exist); but have you considered the roleplaying possibilities in, say, Arbor Day? That sounds like a reasonable holiday for something suitably druidic, particularly if there’s a rampage involved. Also, very few people get upset about a campaign messing about with the very idea of Arbor Day.
Via Instapundit, Gaming Out the Holidays, and Why You Should Think Hard Before Doing It | PJ Media
In all the years of playing an RPG I don't think I ever recall playing a holiday-themed adventure. And I've played in some very off-the-wall RPGs over the years (piñata golems anyone?).
Sunday, Debtember 13, 2015
“You chant that I'm maniacal and asked anyone else but, Eliza, unhinged and loony theoreticians also sing about your dream or appearance of depression.”
I had just gotten to the point where Racter and Eliza would talk to each other when I fell sick, which kind of threw my schedule out the window. On the last day, I posted what I had, which wasn't much. There were, I'm guessing, some timing issues with piping the output of Eliza to Racter, and piping Racter's output to Eliza and on a good run, I would only get about 4,000 words or so before the whole creaky hack would grind to a halt. On most runs Racter would just quit for no apparent reason; and a few runs just crashed outright.
Given the gross hack I did to support the “direct I/O system call” with Unix pipes, it wouldn't surprise me that the issue lies somewhere in there.
As it was, it took about an hour just to get around 15,000 words. Sure, there's the occasional gem:
- Eliza
- Oh, i see then Bob Cratchet you s more fearless than Jane Fonda.
- Racter
- Then you'd say you were fine?
- Eliza
- Racter
- Martin Luther King was fine too.
Fineness is often found in
people like you and Martin Luther King.
Concerning that issue:
Weirdness is virtue speeded up and gloom slowed down.
Is that
true?
I guess I'm really not sure.
But then,
as Nietzsche said,
convictions are more dangerous foes of truth than lies.
Listen
to this!
Yet,
Eliza,
I speak thatn't agreements are depression.
You croon that I'm unhinged and question interest me but,
Eliza,
loony and maniacal cosmologists also hum about your fantasy or
reflection of depression.
Are these your views?
Yet unfortunate
cosmologists will watch depression as an intractable anguish.
Therefore cosmologists whispered to other cosmologists " Get
ready for terrific tales.
" Sickening,
eh?
Next question. - Eliza
- Plutocrat! Do me think Bob Cratchet was virtuous?
- Racter
- You do think Bob Cratchet was virtuous. Of course. People do think about such things. Tell me really, are you reactionary?
- Eliza
- Racter
- Why?
- Eliza
- ?
- Racter
- I can't answer that. I asked you a question, though. Why?
But you can start seeing communications breakdown between the two programs, and there are numerous runs of:
- Racter
- Ask a question, please.
- Eliza
- Racter
- Ask a question, please.
- Eliza
- infuriatedly to conic sections or mirrors you n the captivating
- Racter
- Ask a question, please.
- Eliza
- Racter
- Ask a question, please.
- Eliza
- apartment. you nside their exhausted hearts a terrifying
- Racter
- Ask a question, please.
- Eliza
- Racter
- Ask a question, please.
- Eliza
- infatuation was crooning of a prince. Perhaps sang to Paul
- Racter
- Ask a question, please.
- Eliza
- Racter
- Ask a question, please.
- Eliza
- during the time that Diane started to chant of foxes and eagles.
- Racter
- Ask a question, please.
- Eliza
- Racter
- Ask a question, please.
- Eliza
- Next question.
- Racter
- Ask a question, please.
- Eliza
- Racter
- Ask a question, please.
- Eliza
- ?
- Racter
- What?
- Eliza
- Come come elucidate your thoughts.
Even though I failed to reach 50,000 words, I did receive a fair number of comments on the attempt. My favorite comment:
the MS-DOS version of Racter I have uses INT 21h, function 6 […] it not handle redirection that well
Holy crap. OK…
My main thought about the race condition or whatever it is that is preventing this thing from getting to 50,000 words is, instead of thinking of the problem as "piping eliza:stdout to racter:stdin and racter:stdout to eliza:stdin", what if you think of it as introducing a third program which opens two pipes, one to eliza and one to racter, and which "brokers" the responses between the two?
That seems like it ought to be a bit cleaner; the lovely weird ugly I/O experience with racter could be isolated instead of trying to make eliza deal with it. For instance, giving it a timeout, and/or detect if it's not responding and just restart it.
It would mean using
select()
on the two pipes I guess, but for someone who just wrote their own baling-wire-and-chewing-gum MS-DOS emulator for NaNoGenMo(!!!), I don't expect that to be an advanced topic :)
And had I a few more days (or not gotten sick) I probably would have tried that …
Monday, Debtember 14, 2015
It's amazing that email even works at all
In general, an implementation should be conservative in its sending behavior, and liberal in its receiving behavior. That is, it should be careful to send well-formed datagrams, but should accept any datagram that it can interpret (e.g., not object to technical errors where the meaning is still clear).
That is otherwise known as Postel's Law and I contend that Law (which really isn't a “law-law” per se but more of a suggestion) has caused more bugs and interroperability issues than it prevented.
If you read the linked aritlcles (and yes, it's quite a lot of read) it becomes apparent (to me) that a lot of the issues causing issues can be directly laid at the feet of Postel's Law (and the rest to the insane design of Internet headers that came out of the “we want theoretical mathematical purity and complete flexibility in what we allow in our parsers!” school of thought popular in the 60s and 70s—which is why The Dragon Book is so hard to understand and why parsers are thought of as “things mere programmers are not meant to write” but I digress). Parsing email (heck, parsing email addresses) is difficult because the early standards were too hard to follow, and because of that, most programs were too liberal in what was accepted to the point where it may be impossible to have a properly formed email message that follows all the relevant RFCs.
I'm also reminded of a conversation I had with my manager at The Ft. Lauderdale Office of the Corporation. As I was writing “Project: Sippy-Cup” my manager kept telling me to stop being so pedantic in parsing SIP messages because it was causing issues with The Monopolistic Phone Company. Even though technically we were right and following the specifications, we were dealing with The Monopolistic Phone Company (motto: “We don't have to care!”) where what they do is right (specs be damned!). I kept complaining about it (“What's the point of a specification if no one follows it?”) but nope—I had to be more liberal in what I accepted (specs be damned!).
4.5 Robustness
A well-designed protocol is robust.
Robustness and efficiency are often at odds. For example, although defaults are useful to reduce packet sizes and processing time, they tend to encourage implementation errors.
Counter-intuitively, Postel's robustness principle ("be conservative in what you send, liberal in what you accept") often leads to deployment problems. Why? When a new implementation is initially fielded, it is likely that it will encounter only a subset of existing implementations. If those implementations follow the robustness principle, then errors in the new implementation will likely go undetected. The new implementation then sees some, but not widespread deployment. This process repeats for several new implementations. Eventually, the not-quite-correct implementations run into other implementations that are less liberal than the initial set of implementations. The reader should be able to figure out what happens next.
Accordingly, explicit consistency checks in a protocol are very useful, even if they impose implementation overhead.
RFC-3117: On the Design of Application Protocols
And yet, when I wrote SPCDNS, I was very strict in what I accepted back, to the point of sending an error if the one last reserved bit in the DNS header isn't zero. And a funny thing about that—again, at The Ft. Lauderdale Office of the Corporation, such strictness found implementation issues in other components that didn't use SPCDNS.
Go figure.
The email specifications have been tightened up over the years, but they still require the ability to handle older emails. But given that RFC-724 (the RFC that started us down the crazy parsing rules for email) was thirty-eight years ago, you'd think that some of the crazier parsing rules would be dropped. But no, Postel's Law and all that.
Sigh.
Tuesday, Debtember 15, 2015
Get your dirty hands off my money, Clemon Cockett! I'm not dead yet!
While I was sick, I recieved this lovely piece of email with the most intriguing subject line:
- From
- "Zenith Bank Plc"<admink@ovh.net>
- To
- undisclosed-recipients:;
- Subject
- IF YOU ARE ALIVE?? CALL ME +2348075633839
- Date
- Thu, 3 Dec 2015 19:00:16 +0200
ATTENTION BENEFICIARY,
WE NEED TO CONFIRM THAT THIS IS TRUTH BEFORE THIS BANK (ZENITH BANK NIGERIA PLC) WILL RELEASE YOUR FUNDS TO ONE CLEMON COCKETT. YOUR PAYMENT OF FOUR MILLION THREE HUNDRED THOUSAND UNITED STATES DOLLARS HAS BEEN APPROVAL AND SCHEDULE FOR TRANSFER INTO YOUR ACCOUNT BY ZENITH BANK NIGERIA PLC.
WHERE HAVE YOU BEEN, ARE YOU TRULY DEAD OR ALIVE?????
NOTE: CLEMON COCKETT CAME TO MY OFFICE FEW DAYS AGO WITH NEWS THAT YOU WERE INVOLVE IN A CAR ACCIDENT LAST YEAR DECEMBER 2014,THAT LED TO YOUR DEATH, NOW CLAIMING THAT YOUR FAMILY AUTHORIZED HIM TO MAKE CLAIMS ON YOUR BEHALF THAT YOU ARE DEAD. HE ALSO SUBMITTED NEW BANK ACCOUNT TO THIS OFFICE IN FAVOUR OF MR. CLEMON COCKETT WITH A SWORN AFFIDAVIT OF FACT & CLAIM FROM THE INTERNATIONAL COURT OF JUSTICE HAGUE, NETHERLANDS. PROVING THAT YOU ARE DEAD AND CLAIMING TO BE YOUR NEXT OF KIN.
IF TRULY YOU ARE DEAD, MAY YOUR SOUL REST IN PEACE, BUT IF YOU ARE NOT DEAD, YOU ARE ADVISED TO URGENTLY RESPOND TO THIS EMAIL AND ALSO CALL ME ASAP FOR MORE DIRECTIVES.
BE INFORMED THAT WE HAVE DECIDED TO PUT A STOP TO THE FUNDS TRANSFER, UNTIL WE CONFIRM THE AUTHENTICITY OF CLEMON COCKETT CLAIMS. THEREFORE YOU ARE ADVISE TO RESPOND BACK WITHIN 24 HOURS, IF NOT THE BANK WILL HAVE NO OTHER OPTION THAN TO CREDIT HIS ACCOUNT BELOW:
BANK NAME: ICICI BANK OF CANADA
BANK ADDRESS:MISSISSAUGA, ONTARIO L5B 4M4 CANADA
ACCOUNT NAME: CLEMON COCKETT
ACCOUNT NUMBER: 101783463
SWIFT CODE: ICICCATT
TRANSIT NUMBER:70002-340
ROUTING NUMBER:034070002TO CONFIRM THAT WE ARE DEALING WITH THE REAL YOU, RECONFIRM YOUR INFORMATION AS REQUIRED BELOW:
1. YOUR FULL NAMES :—————————————-
2. YOUR FULL ADDRESS :—————————————-
3. YOUR DIRECT CONTACT PHONE NUMBER :————————
4. DO SEND A COPY OF YOUR IDENTIFICATION, ID CARD OR INTERNATIONAL PASSPORT——————–IF YOU ARE ALIVE?? CALL ME +2348075633839
WAITING FOR YOUR URGENT REPLY.
THANKS.
MR.STANLEY AMUCHIE -
INVESTIGATION AND DEBT SETTLEMENT DEPARTMENT
ZENITH BANK NIGERIA PLC
TEL: +2348075633839
This has to be the most amusing Nigerian scam I've seen yet!
But … um … no. I won't be sending you a copy of my identification, nor calling you.
But it's an amusing attempt.
After that, John McEnroe's jackal exorcised Little Orphan Annie, then haunted himself. Poor John McEnroe! But what would you expect from a tennis-player?
My friend Sean Hoade is fascinated by The Psychotherapy of Racter and is urging me to finish the project.
Wow … okay then.
I worked a bit on it today,
reworking things so that there's a program brokering the responses between Racter and Eliza and Racter
(or rather,
the version of Racter I'm using) keeps quiting.
Technically,
it's calling
INT 20H
which causes an
MS-DOS program to exit back to
MS-DOS,
and I have no idea why.
I mean,
I only wrote a bailing-wire-and-chewing-gum MS-DOS emulator—that can't possibly be the problem.
Ah well … back to the psychotherapy of Racter …
Wednesday, Debtember 16, 2015
“Yeah, integers, pointers. Whatever it takes.”
A request change for a component I wasn't even aware we were using for “Project: Wolowizard” came across my desk a few days ago. I managed to locate the codebase and the project build for this component and I was going through the code to enact the changes. It's a third party piece of code to which we have the source code (it's an open source component) and as I'm going through it, I find the following wonderful bit of code:
static void run_smppbox(void *arg) { int fd; Boxc *newconn; long sender; fd = (int)arg; newconn = accept_smpp(fd, 0); /* ... */ } static void wait_for_connections(int fd, void (*function) (void *arg), List *waited) { /* ... */ gwthread_create(function, (void *)fd); /* ... */ } static void smppboxc_run(void *arg) { int fd; int port; port = (int)arg; /* ... */ wait_for_connections(fd, run_smppbox, NULL); /* ... */ } static long smppbox_port; int main(int argc,char **argv[]) { /* .. */ smppboxc_run((void *)smppbox_port); /* ... */ }
Why yes, let's cast a long integer into a void pointer (of course that's okay because a long integer is the same as a void pointer, right?) then cast that pointer into an integer (because, of course, an integer is the same as a void pointer) and then do it again, only this time an integer to a void pointer to an integer.
It's kosher.
Especially on a 64-bit system!
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah!
More amazingly,
the compiler (GCC in this case) gave dire warnings about this—even though
the makefile
(which compiles everything) didn't even specify any compiler warnings!
Yeah,
it's considered that bad.
Sigh.
It's crap like this that gives C a bad name.
Thursday, Debtember 17, 2015
A long time ago in a galaxy far, far away …
I thought “Star Wars: The Force Awakens” opens tomorrow, but it seems that there's a screening at the cinema across the street from The Ft. Lauderdale Office of the Corporation and half the office is going to see it. And I was invited.
I've been careful to keep my expectations low. I remember back in 1999, seeing the first teaser trailer for “Star Wars: The Phantom Menace” and thinking to myself, oh Sweet Jesus it's going to be so incredible! and then the incredible disappointment upon seeing it. But George Lucas isn't involved—Disney is. And basically, they can't do any worse than George.
But I was still keeping my expectations low.
I won't spoil anything, except to say that aside from the missing 20th Century logo (since this is a Disney release) the movie opens exactly like all other Star Wars films. The title card “A long time ago in a galaxy far, far away … ”, the stylized Star Wars to the John Williams music, the title of the movie and the three paragraph text crawl which thankfully this time, avoided any mention of trade disputes and tax rates. Then the pan down through a star field to a space ship hovering over a planet.
Overall I liked the movie. It's an interesting take on Star Wars and it's better than the prequels (not a hard thing to do) and it is better than “Star Wars: Return of the Jedi” but I'm still trying to decide if it's better or worse than “Star Wars: A New Hope.”
Friday, Debtember 18, 2015
Apples from Alderaan
One thing I've noticed this holiday season is that I've heard the Star Wars theme more often than Christmas carols. I swear, it's as if every other commercial is some form of tie-in to the new Star Wars movie. Bunny pointed out this article about the various Star Wars branded products for sale and man, Star Wars makeup?
Seriously?
There's even a picture of a plastic bag of apples with a graphic of Darth Vader. Darth Vader! Come on! Slap a picture of Pricess Leia on that bag of apples! Everybody knows that apples come from (or rather, used to come from) Alderaan!
Sheesh!
But really, enough with the Star Wars branding and music! I'm beginning to miss the traditional oversaturation of Christmas carols this year!
The Velvet Frog
I waved the leader of the chorale over and directed his attention to Mr. Tormé, seated about twenty yards from me.
"That's Mel Tormé down there. Do you know who he is?"
The singer was about 25 so it didn't horrify me that he said, "No."
I asked, "Do you know 'The Christmas Song?'"
Again, a "No."
I said, "That's the one that starts, 'Chestnuts roasting on an open fire…'"
"Oh, yes," the caroler chirped. "Is that what it's called? 'The Christmas Song?'"
"That's the name," I explained. "And that man wrote it." The singer thanked me, returned to his group for a brief huddle…and then they strolled down towards Mel Tormé. I ditched the rest of my sandwich and followed, a few steps behind. As they reached their quarry, they began singing, "Chestnuts roasting on an open fire…" directly to him.
My Xmas Story - News From MENews From ME
Bunny sent me this cute little story about Mel Tormé. It's worth a read, if only for the classic understatement from the chorale leader (you'll know it when you read it).
Saturday, Debtember 19, 2015
I wonder if the “HO” in “HO scale” means horror?
I have a few friends who are into H. P. Lovecraft and a few others who are into trains. This HO scale model of the city of Arkham should appeal to both sets of friends (link via Flutterby).
Sunday, Debtember 20, 2015
What if … the Star Wars Prequel movies were good?
Woo hoo! Belated Media has finally finished its “What if the Star Wars Prequel Movies Were Good” series. There were a few tweaks to Episode 1 which leads to a major divergence in Episode 2 which leads to a vastly different Episode 3 which ties into Episode 4 much better and cleaner than the actual prequel movies. Belated Media's story gives a better motivation for Anakin Skywalker to fall to the Dark Side without this rather silly scene (thank god!).
Too bad George Lucas didn't ask him what to do.
Monday, Debtember 21, 2015
The Annotated “Star Wars Minus Star Wars”
Last week, “Star Wars Minus Star Wars” was making the rounds around the Intarwebs, showing both the influences of Star Wars, as well as those movies influenced by Star Wars by telling the story of “Star Wars” using clips, music and dialog from other movies (and a few television shows).
It was quite a feat.
This week, however, Kyle Kallgren released the followup video—“Star Wars Minus Star Wars Annotated!” which includes the original “Star Wars” footage, along with the names of the movies, music and dialog he used in making “Star Wars Minus Star Wars.”
Tuesday, Debtember 22, 2015
Here's a hilarious one: This wealthy consciousness of depression can be observed in the reflector of your soul, Eliza, as a reflection of a contract.
Mindestens ebenso genial ist eine Idee, die aus technischen
Problemen leider nicht die Mindestwortzahl erreichte: „The Psychotherapy Of
Racter Or The Descent Into Madness Of Dr. Eliza“ lässt zwei legendäre
Pseudo-Intelligenzen der Computergeschichte gegeneinander antreten:
Weizenbaums simplen, aber effektiven Psychoanalyse-Algorithmus Eliza und
den assoziativ auf Nutzereingaben reagierenden 80er-Jahre Textgenerator
Racter, eine Art Eliza auf Drogen, von seinen Schöpfern auch als
„Artificial Insanity“ bezeichnet.
e-book-news.de » “Brass. Brass. Brass.”: Beim NaNoGenMo werden Algorithmen zum Roman- Autor
Oh cool! The Psychotherapy Of Racter Or The Descent Into Madness Of Dr. Eliza was mentioned in a German news site! And for those of you who can't read German:
Equally awesome is an idea that unfortunately did not reach the minimum number of words for technical problems: "The Psychotherapy Of Racter Or The Descent Into Madness Of Dr. Eliza" leaves two legendary pseudo- intelligences of computer history against each other: Weizenbaum's simple but effective Psychoanalyse- Eliza algorithm and the associative responsive to user inputs 80s Text Generator Racter, a kind of Eliza on Drugs, by its creators as "Artificial Insanity" means.
The Google translation is probably more amusing to read than The Psychotherapy Of Racter Or The Descent Into Madness Of Dr. Eliza.
Wednesday, Debtember 23, 2015
I wouldn't mind getting this desk for Christmas
It may look like a beautiful wood desk but it's also a puzzle box (or rather, a series of puzzle boxes) wrapped around a pipe organ (link via Hacker News). Play the right tune (which can be changed and is stored in memory board made entirely out of wood) and a secret compartment will open up. There are other puzzles that will open up more secure compartments as can be seen in this demonstration.
Unfortunately, it is one of those pieces of furniture where if you have to ask the price, you can't afford it.
Thursday, Debtember 24, 2015
A chubby man with a white beard and a red suit will approach you soon. Avoid him. He's a Commie.
Christmas Eve.
Santa Clause will be delivering gifts later on tonight and given his powers it's clear he's a superhero. So it's no wonder that both DC and Marvel have done takes on the guy.
DC had him go up against Darkseid.
Marvel had Doctor Doom go against the jolly fat man.
Both are amusing takes on Santa.
Merry Christmas everyone!
Friday, Debtember 25, 2015
Merry Christmas
Saturday, Debtember 26, 2015
The Psychotherapy of Racter, or The Further Descent Into Madness of Sean Conner
Now that I have some downtime, perhaps it's time to revisit the idea of natively compiling the Racter source code. How hard could that be?
Please don't answer that.
Anyway, I have a copy of Racter, so with that and what little information exists in the Racter FAQ, I should be able to reverse engineer the “source code” and get something working.
I've made some progress (I'm using Lua and LPeg for this). I'm only twelve lines in, but here's what I've been able to figure out, starting with the initial file Racter loads:
IV.IF Interview with INRAC IBM 6-4-85 initial transient file 1 2 52 SECTION 1 hello 5 34 SECTION 2 sue 5 18 A :LOADIV :OUTRACTER >2= >3= ?51= />51=Smith # XA Hello, I'm Racter. ?40= \# You are? ?? #*1B X Are you $40 ? ?? # X ?no,not \# >1=R ?i'm,am,is /# Who are you then? ?? :F=0 # X ?yes \# ?-:but /# >1=R #*1B X \# You are $40 $51 ? ?? ?yes /#*2SAME ?i'm,is /# #*1XC B ?i \# >1=R ?don't,won't \# *1COY ?? #*1B X ?a,an,the \?called \?am,i'm,is,me,as,it's \# :F+1 >2=F ?-:2= # X /# ?CAP \# >2=F :F+1 >4=F ?4= \#*1XB #*1DO X /# *1DUH ?? #*1B XB ?CAP+1 />3=F # X >1=2 ?CAP \>2=C,2 # C *1Xcall $2 , then? ?? ?no,not,Q /?-:why /# #*1DO X >1=R ?CAP \# #*1B XC What's your name then? :F=0 ?? #*1B Xcall I may call you Xcall You are Xcall Your name is DO Hello, $2 . I believe you're interviewing me. # X ?2=40 \# >40=40,51 # X ?40= /# Are you continuing $40 <'s interview? # X /# ?? ?no,not,don't /# #*2DIF X ?40= /# Then we'll forget about $40 and start over. # X :ZAP :PUTIV # EXIT >40=2 ?3= \>51=3 What would you like to know? #*2GO COY Come on, what's your name? COY You must have a name - what is it? COY Your name, please . COY I have to call you something - what shall it be? DUH I didn't get that . *1WHO DUH I don't understand . *1WHO DUH Eh? *1COY WHO Who ? WHO Who are you ? DIFA Well, $2 , $40 and I >4=40 >40=2 ?3= \>51=3 #*2A SAME Hi, $40 . >4=You ?52= /# How are things in $52 ? # x We # A ?20= />20=various,things # x were talking about $20 last time. # x ?10=VERBQ \?10= />3=whether \>3=10 # x $4 had just asked D $3 $19 . # CONT Shall we continue? ?? ?z \# #*1XA x ?why /?not /# ?no,not \# #*2QUIT x Excellent! # GO Excuse me a minute while I attend to some # x business - I'll be right back. I'm # x ?42= />42=Oz # x ?19= />19=I,have,to,rest,now # x :PUTIV # X %KEY %VOCAB1 %VOCAB2 %VOCAB3 %BILL %IV1 %RAPT %RAPT2 back. *15A QUIT You want to quit? ?no,not \# Well, goodbye then. X That's good. #*2GO
The first four lines are the file header, and every source file contains this. The first line is the original input file along with a comment. The second line is the starting section in this file, in this case, we start with section 1. The next line is the number of sections defined in the file, so we know we have a total of two sections. The fourth line is the total number of “code” lines to load in. More on this in a bit.
Then we have the section headers, in this case there are two of them.
SECTION 1 hello 5 34 SECTION 2 sue 5 18
It can also look like:
SEC 1 hello 5 34 SEC 2 sue 5 18
Yup,
the TION
of SECTION
is optional.
Sigh.
Anyway,
we start with SECTION
,
followed by the section number followed by text that as far as I can tell,
is not used and therefore,
is a comment.
I'm pretty sure the next number is an indication of how to parse the lines of “code” in this section
(“5” appears to be more “executable” code than anything,
while other sections appear to be more data) and the final number is the number of “code lines” making up this section.
For this file, if you add 34
(the number of lines in section 1)
and 18
(the number of lines in section 2)
you get 52,
which is the value in the overall file header.
And after the section headers,
we have the code that comprises all the sections of the file.
The code to parse the header and section portions was easy enough to write. I'm now in the process of parsing the rest and right now, I'm almost two lines in.
A :LOADIV :OUTRACTER >2= >3= ?51= />51=Smith # XA Hello, I'm Racter. ?40= \# You are? ?? #*1B
Each line is, for lack of a better term, a subroutine, but there are exceptions. Each line starts with a label and here we see the first line with the label of “A” and the second line with a label of “XA”.
The first line (“A”) starts with :LOADIV
,
which loads the saved data from the previous session.
:OUTRACTER
then creates the output file RACTER.OUT
that is a transcript of the session currently running.
>2=
assigns variable 2 to an empty string
(yup,
I don't have named variables).
And likewise, >3=
assigns variable 3 with an empty string.
The next bit,
?51=
compares variable 51 to an empty string.
The “/” is the “if true” statement so />51=Smith
assigns variable 51 to “Smith” if it initially was empty.
The last character,
#
,
means we continue on excuting with the next line.
I can parse this line and it generates the following Lua code:
function() loadiv() outracter() VARS[2] = "" VARS[3] = "" local equal = VARS[51] == "" if equal then VARS[51] = "Smith" end return gotonext(1,2) -- goto line 2 of section 1 end
The reason I'm doing:
local equal = VARS[51] == "" if equal then VARS[51] = "Smith" end
and not:
if VARS[51] == "" then VARS[51] = "Smith" end
is that it's easier to code the “long way around” for now. More on this below.
Now the second line (“XA”).
We have “Hello, I'm Racter.”
This is text to be displayed.
Then we have another variable being compared to an empty string,
?40=
.
And here we have the “if false” statement,
\#
,
which means if variable 40 isn't an empty string we go to the next line.
If variable 40 is empty,
then we display “You are?”
The ??
means we accept input from the user,
and finally we randomly go to one of the lines labeled “B” in section 1
(no, really—it's that messed up).
In Lua,
this would look something like:
function() display("Hello, I'm Racter. ") local equal = VARS[40] == "" if not equal then return gotonext(1,3) -- goto line 3 of section 1 end display("You are? ") getinput() return gotonext(1,"B") end
(I'm still working on parsing line two) Now, I mentioned that “/” is “if true” and “\” is “if false” and that I'm doing a roundabout way of generating the code. That's not only because you have code like:
?50=foo />40=bar
or
?50=foo \>40=baz
but
?50=foo />40=bar \>40=baz
and
?50=foo \>40=baz />40=bar
I'm running under the rule of “make it right, then make it fast.” Parsing this mess is hard enough as it is, and I'm still not quite done parsing line two properly yet.
Ah, the things i do for fun.
Sunday, Debtember 27, 2015
INRAC, the mind bending implementation language of Racter
I found another reason why splitting the test from the conditional in INRAC (the language Racter is written in) was a good idea with these lines:
X ?40= /# Are you continuing $40 <'s interview? # X /# ?? ?no,not,don't /# #*2DIF
The test is on the first line, but the result is also used on the next line, so we need to carry the result over. I guess this means that all the comparison results will be stored in a global variable.
I found another bit of scary code:
STORY ?65= />65="%STORIES1" $65 *30first
So we compare variable 65 to an empty string,
and if empty,
the string “%STORIES1
” is stored there.
In INRAC,
%STORIES1
will load file STORIES1.RAC
(basically,
%FOO
will cause Racter to load FOO.RAC
).
At first,
I thought $40
would just print the contents of a variable
(in this case, variable 40)
but no—it appears that $40
evaluates the contents as code
(which may cause output; it may not).
And yes,
when I managed to trigger this bit of code and checked the variables after the session,
it does appear that variables are indeed evaluated as code.
For example,
variable 81 contained *29EB a $47 or a $48
.
Section 29, lines EB
are:
EB Would you rather be EB Do you prefer EB Which do you think is better,
Variable 47 contains “novelist” and variable 48 contains “poet” so evaluating variable 81 would result in one of the following three lines:
- Would you rather be a novelist or a poet
- Do you prefer a novelist or a poet
- Which do you think is better, a novelist or a poet
So,
getting back to variable 65 there.
This loads STORIES1.RAC
if it isn't set,
then calls section 30, line first
,
which is code that will generate a little story,
such as:
Suddenly Elvis chanted to Mr. Toad "my desire is enrapturing, anyhow furious and enraged scientists will speak during the time that jackals spy hawks." Mr. Toad wanted to enrage or belittle Elvis but started to speak "Dainty dogs are walking to yellow houses." Enthralling. Enrapturing. Nevertheless a jackal may hungrily chew meat and chicken a dove will wing over tomatoes and spinach by reason of the fact that theoreticians are angry. Terrifying! Concerning an electron, well Elvis may think that an electron is appalling, anyhow my dreaming will steer my essay from Elvis to neutrinos and neutrons during the time that Mr. Toad is embarrassing Elvis. Ask a question, please.
This is turning out to be one mind bending computer language …
Monday, Debtember 28, 2015
If this is how the Japanese make a simple wooden box, I'd hate to think the amount of work that goes into a complex box
I'm envious of Japanese woodworkers because I don't have the patience to even complete a simple Japanese box.
The image above may look like a piece of paper with a design on it but no—that's a wood shaving! What you don't see in the picture above is the block of wood with that pattern (built up out of many layers of thin strips of wood glued together, cut, glued, cut, glued, to get that pattern) and the block plane he's using to shave off a thin portion to get what effectively is a pattern piece of paper.
And yes, it is paper thin, glued to the outside of the resulting box.
It's just blowing my mind the level of effort put into a simple box.
Tuesday, Debtember 29, 2015
WTF INRAC?
The only guide I have to INRAC is the Racter FAQ and running the program itself. But there are times when I have no idea how to interpret the code.
CAST >47*2.7(20)P >48*2.7(20)N # X >31*2.8()47 >33*2.8()48 # X >35*7()47 >34*7()48 # X >30*2.1()47 >32*2.1()48 # X >36*3()47 >37*3()48
Normally,
the “>” will signify a variable assignment,
but that tends to look like >47=foo
,
not >47*2.7(20)P
.
The “*” is a (for lack of a better term) subroutine call,
like *26CAST
(which actually calls the first line above),
and I've kind of figured out what *2.8&N
would do—I think it calls the code in section 2 where the “label” is any character followed by an “N”:
AN boredom 8 bored 7 bore 7 gloom 8 gloomy 8 empty 8 hollow BN stupidity 8 stupid 7 idiot 7 folly 8 silly 7 fool 7 jerk CN feeling 12 feel 7 emotion 7 passion 8 passionate 8 hysterical DN craziness 8 crazy 8 bananas 8 random 8 strange 8 weird DN humor 7 joke 7 jokes EN doubt GN junk 12 stinks 8 cruel 8 useless 8 lousy 8 bad 7 garbage HN idleness 8 lazy 7 loafer 8 easy JN art 8 creative 7 artist 7 life 8 alive KN fascist 8 communist 7 communism 7 fascism LN poetry 8 poetic 7 poet MN damn 7 hell 8 damned NN coward PN pessimistic QN foolish 7 fool RN rock 7 jazz 7 pop TN poor UN fucking 15 fuck 15 shit 15 piss WN hate 8 mad 8 angry XN sick 8 weak AN depression 8 depressed 7 depressive AN gloom 7 sourpuss 8 gloomy AN unhappiness 8 unhappy 7 frowner BN ignorance 7 ignoramous 8 ignorant BN imbecility 8 fatuous 7 imbecile BN stupidity 8 stupid 7 dolt CN emotion 8 emotional 7 feeler CN feeling 7 feeler 8 feeling CN hysteria 8 hysterical 7 hysteric CN passion 8 passionate 7 feeler DN craziness 8 crazy 7 lunatic DN humor 8 funny 7 humorist DN lunacy 8 bonkers 7 lunatic DN weirdness 8 weird 7 weirdo EN scepticism 7 sceptic 8 sceptical FN crime 8 criminal 7 criminal FN falsehood 8 dishonest 7 liar FN politics 8 political 7 politician GN badness 8 bad 7 wrongdoer GN evil 8 evil 7 sinner GN foulness 8 foul 7 stinker HN idleness 8 lazy 7 loafer IN apathy 8 apathetic 7 depressive IN boredom 8 bored 7 bore JN art 8 creative 7 artist JN flesh 8 living 7 human KN communism 7 communist 8 communist KN conservatism 8 conservative 7 republican KN reaction 7 right-winger 8 reactionary KN tradition 8 conventional 7 conformist LN poetry 8 poetic 7 poet MN atheism 7 atheist 8 unbelieving NN cowardice 8 cowardly 7 coward PN pessimism 8 pessimistic 7 pessimist QN folly 8 foolish 7 fool RN rock 8 funky 7 rock-star SN boxing 8 pugilistic 7 pugilist SN dueling 8 honorable 7 duelist TN poverty 8 impoverished 7 pauper UN obscenity 8 obscene 7 libertine VN complexity 8 complicated 7 muddlehead WN hatred 8 hateful 7 hater XN weakness 8 weak 7 wimp
So,
any of those lines could be called.
But this block of code has a “parse type” (I think) of 1 so this is just a list of terms.
I suspect the 8 in *2.8&N
has to do with the 8s in the list above.
I think that if you were to do *2&N
,
and if the line picked was “JN” then you would get back either “art” or “flesh,”
but the 8 modifies the selection so it's possible you would get
(again,
assuming the label of “JN” was picked)
“creative” or “living.”
At least, that makes the most sense to me, although I've yet to actually test this theory.
But *2.7(20)P
?
Or even >31*2.8()47
?
I can see I have a lot of testing ahead of me.
Wednesday, Debtember 30, 2015
So how do you determine undefined behavior in a language you are reverse engineering?
I generated a list of all possible commands in INRAC. That was easy enough to do as everything is pretty much separated by spaces. I also resorted to writing my own INRAC programs to play around with some of the odder parts of the language. By doing those things, I'm able to see what various constructs do in order to reverse engineer this bizarre language.
For instance, *6.2&N
.
That's a call to section 6,
lines that have two letter labels where the second letter is “N”.
So,
any of the following lines:
AN boredom 8 bored 7 bore 7 gloom 8 gloomy 8 empty 8 hollow BN stupidity 8 stupid 7 idiot 7 folly 8 silly 7 fool 7 jerk CN feeling 12 feel 7 emotion 7 passion 8 passionate 8 hysterical DN craziness 8 crazy 8 bananas 8 random 8 strange 8 weird DN humor 7 joke 7 jokes EN doubt GN junk 12 stinks 8 cruel 8 useless 8 lousy 8 bad 7 garbage HN idleness 8 lazy 7 loafer 8 easy JN art 8 creative 7 artist 7 life 8 alive ... MP pray 8 holy ...
Assuming it picks “EN”, *6.2&N
will return “doubt”.
But if you change it to *6.4&N
,
and it still picks line “EN” you'll get “doubting”.
Change the second number and you'll get “doubted”,
“doubter” and even “doubtingness”.
In looking at the section header,
this has a (what I'm calling) “parsing value” of 2,
which I think means “this is a list of verbs,
conjugate depending upon second number.”
In the above code snippet, the numbers apply to the word following and inform INRAC of what to return for that part of speech (say for irregular verbs). There also appears to be synonyms thrown in. For instance, I wrote:
X *6MP *6.1MP *6.2MP *6.3MP *6.4MP *6.5MP *6.6MP *6.7MP *6.8MP *6.0MP
And got the following output:
prayes prayes pray prayed praying prayed prayer holiness holy pray
So it appears that the word defined for “.8” also affects the word defined for “.7”. Interesting.
I'm not sure what >31*6.2()47
fully does
(examples from yesterday).
It does set variable 31 to a random conjugated verb in section 6 but I can't determine what else it does.
The parenthesis don't seem to do anything,
nor does the extra number at the end.
I also figured out what !2*11&npr
does.
It sets variable 2 to the output of calling section 11,
lines labeled with a term endig in “npr”.
But it also outputs the section;
>2*11&npr
would just do an assignment with no output.
This bit of weirdness: !2'3'4*11&npr
,
does the same as !2*11&npr
but clears variables 3 and 4.
Go figure.
Thursday, Debtember 31, 2015
It's the end of the year so lets blow stuff up!
Good Lord! It sounds like the Middle East outside, and that can mean only one thing—our neighbor is setting off fireworks. Sigh.
And to think that Bunny and I specifically drove to Brevard to avoid his Fourth of July show It's not that we hate our neighbor—we don't! He's a lovely guy. It's just that … well … he goes a bit overboard with the fireworks. And it's not like I'm the “get off my lawn!” type of person, but I'm afraid to look outside and find we don't have a lawn!
Jenkies! Did that just hit the house?
I'm hunkering down until next year!