MacBook, defective by design banner

Put the knife down and take a green herb, dude.

One feller's views on the state of everyday computer science & its application (and now, OTHER STUFF) who isn't rich enough to shell out for

FOR ENTERTAINMENT PURPOSES ONLY!!! Back-up your data and always wear white.
URLs I want to remember:
* Atari 2600 programming on your Mac
* joel on software (tip pt)
* Professional links: resume, github, paltry StackOverflow * Regular Expression Introduction (copy)
* The hex editor whose name I forget
* JSONLint to pretty-ify JSON
* Using CommonDialog in VB 6 * Free zip utils
* that hardware vendor review site I forget about is here * Javascript 1.5 ref
* Read the bits about the zone * Find column in sql server db by name
* Giant ASCII Textifier in Stick Figures (in Ivrit) * Quick intro to Javascript
* Don't [over-]sweat "micro-optimization" * Parsing str's in VB6
* .ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); (src)
email if ya gotta, RSS if ya wanna RSS, ¢ if you're keypadless
Monday, January 26, 2015

I wanted to see if JSHint had a provision for [checking imported packages for property names in a file it was, um, "hint"ing](, and ran into a link to the, ["Why I forked JSLint" post]( (which was down -- domain now points to github? -- but lives at again.

The post is interesting. The representative example given to fork JSLint is a horrible one, imo. Kovalyov argues that he should be able to put a `var` before a iterator variable, like this...

`for ( var name in obj ) { ...`

That's really not a good reason to leave JSLint. Forcing you to acknowledge variable hoisting doesn't seem that objectionable. There are other things that it forces you to do that I don't see as much wisdom in, but this really isn't one of them. And that his snippet has "Example taken from jQuery 1.4.2 source" as if that made it automatically something worth emulating also gnaws at my craw a bit.

But the post's [epigraph from Crockford]( does resonate:

>Your sadly pathetic bleatings are harshing my mellow. —Douglas Crockford.

Wow. Reminds me of the [link]( I use in my StackOverflow profile to undercut where I quote, "You should take JSLint's advice," a bit. The guy's a great coder, and I enjoy his very strict approach to JavaScript 99.44% of the time, but Kovalyov is right: Crockford's social skills (and, from what I've seen, hubris) are awful.

But again, bad social skills [don't make the tool just as toxic]( Kovalyov links to Brenan Eich, "creator of JavaScript", where Eich says, "[JS Lint can suck it](" That's said, sure (Eich is using automatic semicolon insertion, though he's doing it to make his code look like [CoffeeScript](, so Kovalyov has already taken the quote *well* out of context), but there's an interesting counterpoint Kovalyov misses in that same blog post from Eich:

>Here's my pitch: committees do not design well, period. Given a solid design, a committee with fundamental disagreements can stall or eviscerate that design out of conservatism or just nay-saying, until the proposal is hardly worth the trouble. At best, the language grows larger more quickly, with conservative add-ons instead of holistic rethinkings.

What I like most about JSLint is that I know I'm getting similar code across the board. **JSLint honestly enforces well-considered conventions.** When Kovalyov says, "It is quickly transforming from a tool that helps developers to prevent bugs to a tool that makes sure you write your code like Douglas Crockford," my reply would be, "And you think your committee is going to do better?"

So many questions about JSLint on StackOverflow get answered with, "You should use JSHint." But if we all use JSHint to turn off whatever bugs us, as we'd do if we followed that advice each time, what do we leave turned on? Just the things that aren't troublesome? Isn't our code getting lint-i-er each time? Show me an example of where what Crockford requires from you is *wrong* -- not just annoying, but undeniably *worse* than an alternative. I don't think it exists, yet.

Isn't the point of a linter to challenge us *all* to write better code?

posted by ruffin at 1/26/2015 12:33:00 PM
Wednesday, January 21, 2015

I've been using Thunderbird again recently because Outlook 2010 wasn't able to connect to the company's Exchange server (although I guess Office365 with OWA might be something different? Maybe Exchange in the cloud? I didn't track things down too far... Outlook, even after updating with a download that the OWA interface said I needed, didn't work), but somehow Thunderbird with the ExQuilla extension ($10 a year) does. Go figure.

I don't hate Thunderbird, but I can see why folks aren't drawn to it. It's very Netscape 3.0-ish and its interface is, at times, horribly unintuitive. It's got *everything*, but everything isn't particularly accessible. I can't imagine if I was coming into Thunderbird cold and hadn't used since, well, early Netscape.

Here's an example.

If you want to set the display font for "plain text" emails in Thunderbird, you have to go to Tools >>> Options, Display, Formatting, click the Advanced button, then click the Monospace drop-down and select a font and size. But I kept getting what many of what were obviously plain text emails in a much larger font than what I'd set.

Turns out that the "Fonts for [Western]" drop-down at the top of the Advanced fonts interface only works for ASCII (I'm assuming) emails. If you want plain text emails in UTF-8 to have a different font than the default as well, you have to choose "Fonts for [Unicode]" from that drop-down. [This bugzilla thread helped]( Not sure why there's a distinction. Perhaps other languages have different fonts for different 7-bit encodings? But shouldn't there just be a concept of a "default" display?

So right. Guess I should've figured that out. /sigh Why you can't just right-click the message you're looking at and set your font (for the whole app) there, I don't know.

posted by ruffin at 1/21/2015 09:55:00 AM
Tuesday, January 20, 2015

Today's headline is essentially the flip-side of a a post by Release Notes' Charles Perry that Marco shared yesterday. The post's conclusions on app revenue would make that Jump to Conclusions guy from Office Space proud:

In fact all apps above number 3,175 on the U.S. Top Grossing list produce enough revenue to at least make its developer [<<< sic!!] the United States household median income for 2014 ($53,891). And this is just for a single app.

Let's pretend his calculations are on the money. I don't know if they are or not. He mentions "Pareto distribution" with the requisite link to wikipedia, and, well, his n equals 1, so it seems legit. ;^)

It seems that even with the revenue curve tilted so heavily towards the big hits, the shape of the App Store still allows room for sustainable businesses to develop in the long tail. It seems that developers who work hard, mind the details, and treat their business like a business have a real chance of making it.

Really? That's Perry's take-home? "A real chance" as in, "if you don't buy a lottery ticket, you don't have a real chance to win"? I really enjoy Perry's podcast, but this post is horribly rose-colored.

Take another look. If your app is top 3175 for an entire year (which it very likely won't be, okay? Check out Exhibit Jared Sinclair), you'll have median income -- about what a reasonably experienced teacher makes, afaict. You know, those folks we always say are underpaid, largely because they deal with our brats day-in and day-out, but let's face it, unlike that of most key-masher engineers, it's not an unseemly, brat-resisting, over-the-top salary.

Again, that's iff your app doesn't fall out of the top 3175 for an entire year. Essentially Perry's pie-ish in the sky-ish numbers don't factor in app ranking churn. What you really need to know is how long it takes for an app like yours to drop from, say, 500 to 4000. I bet it's not very long.

Look, let's put this another way. Let's say that app ranking churn isn't nearly as volatile as I'm betting it is (even though, let's face it, I'm not wrong). If we define median income as our goal, if these numbers are accurate, only 3175 developers worldwide made median income or above on the app store for however long these revenue numbers are accurate. And that's only if each of those apps was written by a one-person shop! Perry does put in a caveat, implicitly asking, "What if you had two apps in there?!" Are we assuming they're both in the top 3175 for a year? Really? Guess what that means for the number of viable professional indie app developers?

And look, let's assume he does has access to non-median revenue fail apps. What did they make? Do they fit the curve and his predictions? What does our ranking over time look like? How long does an app sustain a "median wage" ranking if it breaks into the top 3175?

Each successful app on the way down but still in the rankings is another spot you can't get on your way up. I'd almost rather grow hand-cultivated wheat. Less risk.

These numbers are awful. That's not even a large company's worth of people. Ouch.

Good luck, everyone, in this year's hunger games. Or Thunderdome, or whatever your version of "scarce resources favor predators" metaphor is.

Labels: , , ,

posted by ruffin at 1/20/2015 12:57:00 PM
Monday, January 19, 2015

The right way to make cash on an app.
  1. Table stakes (do what everyone else does)
  2. Killer feature
  3. Lucky launch
  4. Profit
William Wilkinson on Manual, an app that gives your iPhone's camera a "manual" setting on the dial:

I thought Manual was way too niche. How many people actually wanna set ISO on their smartphone? It never crossed my mind that it could exceed Everyday's launch. The launch went so unbelievably well. I was blown away. People were tweeting, the press was great, Apple featured it immediately. Shock and awe. I will toot my own horn and say that the video I made with Oliver helped a lot.
Manual was available for 100 days in 2014. Here’s my dinky:

95,621 total sales.
$123,413 USD total revenue (after Apple’s 30%, before taxes).
$91,773 USD in the first month.

Yeah it was [screwed] up. In terms of up-front expenses it was minimal, the investment is our time. I spent $1,500 on the website, video, sound design, domain, and stock photos. There are no substantial monthly expenses.

Not sure what a "dinky" is, but it seems to have worked out fairly well. ;^)

Though it's worth mentioning he did have a decent team put together to get design done and marketing out. Looks like a little less than three months of work from "noticing" the new camera API to release.
Note that there's lots of luck making evident at that last post too. Timing and targetting new APIs is pretty important. Note that that's _David Smith's MO too.

I submitted Manual a week before the iOS 8 release from Phoot Camp over shaky wifi. Including a fun last minute sprint to create new screenshot sizes for the iPhone 6 and plus. We got lucky and Apple approved Manual a few days later.

Labels: , ,

posted by ruffin at 1/19/2015 11:11:00 AM

A happy coincidence of events -- that Unison, the far and away best OS X usenet client, went free and Google Groups' digest emails started working again -- has me using usenet a little again. Then last week, we have a sign of life on beyond Robert Bernardo's C= user group announcements, which I admittedly do enjoy seeing, and posts by Bravo Sierra Computers, which I might find spammy iff there were real discussions going on. So that's awesome.

But when I go to sign in, of course Teranews, the "free" usenet server that only runs you $3 to sign-up and then promises free access for life, is down. Its web site, rarely updated since it appears to be the early 90s, even recognizes the outage, with a somewhat ominous message that there's no ETA on when it'll be back up. A quickly googled thread on shows it's been down for a week or more.

Time for a fallback, at least for when Teranews is down (just in case it comes back up, which it apparently does each time folks think it's finally given up).

The Netherlands in particular seem to have a number of free options (a list that I haven't vetted is here), but it seemed somewhat convoluted and often not in English. The most popular option doesn't allow posting. I'm going to shy away from that.

I did bump into Astraweb selling blocks of access that don't expire, which looked promising. Since I'm just pulling text on two or three groups I feel nostalgic about, like rgvc, even 5 gigs should be nearly limitless access. I doubt I've pulled that much down from TeraNews -- heck, I wonder if I've pulled in 200 megs -- since I got it in 2007.

While searching for reviews of Astraweb, I ran into this post on reddit that was awfully helpful as it listed a number of block usenet vendors. Seemed time to find out what I could about buying blocks of usenet access rather than just checking out Astraweb in detail.

After stumbling over a usenet review site linked on slickdeals a while back looks like the most important consideration past price is expiration. Atranet, TheCubeNet and NewsDemon, eg, don't have an expiration on their blocks. has a listing of blocks with prices that claims that all of the providers listed don't have an expiration here.

So then it's simply a quick check to make sure there isn't an expiration, and then a price-check for their smallest blocks. Here's my random sample.

TheCubeNet: 5 gigs for $3
NewsDemon: 10 gigs for $2
Astraweb: 25 gigs for $10

The NewsDemon FAQ says the block doesn't expire, and I've seen some not uncomplimentary reviews, so I think I'll give that a shot. We'll see what happens.


posted by ruffin at 1/19/2015 10:12:00 AM
Sunday, January 18, 2015

After thirty years, my stereo amp finally gave up the ghost. I might eventually fix it; I really like its sound. But for now, toast.

Now that I have a new one, I've learned that having a separate component equalizer is a thing of the past. That's really too bad. And I don't have my new amp hooked up to a TV, which is what it apparently now uses to view all your equalizer settings quickly. Not to mention all but one preset assume you have four to five speakers. I should add I'm mostly using this as an output for my iMac and to play vinyl on my 30 year-old turntable (which now needs its own pre-amp for this amp to play it).

I really want to be able to reach over, grab a knob, push up/down a specific band, tweak the sound a touch, and go back to work. I don't want to have to hit seventeen different buttons in a row on my stupid remote (remote?! For a stereo amp? You've got to be kidding me) to make one album sound a little better.

Look, kids, sometimes nostalgia for the past really is remembering a better way of doing things. When we couldn't make everything work through the same digital interface, we could often access different settings with ease. /sigh

Labels: ,

posted by ruffin at 1/18/2015 08:00:00 AM
Saturday, January 17, 2015

I (he said uncontroversially) agree with Jon Skeet -- I'm not sure why converting to quoted printable isn't already in C# somewhere. It's old as the hills, and email seems it'll keep it going for the foreseeable future.

I've seen some wacky ways of trying to do this, but it's really pretty easy. There are only two rules. You take a collection of bytes, here an array, and in the first rule, you only have two options. Either it's a "normal" byte -- which is between 33 and 127, inclusive, but exclusive of 61 (decimal) (since that's the =) -- or it's not. If it is, you add its ASCII char equivalent to the string. If it isn't, you add = plus the string representation of the byte as a two-digit hexadecimal number.

The only monkey wrench is the second rule: that no line can be more than 76 characters, though apparently you can cut any line you want shorter than that. So if the line you're on is 75 characters long already & you're adding a "normal" or if it's 73 characters or greater and you're adding a "non-normal", you need to add a = to the end of the line to let a parser know it's not really a new line of text yet. Then you add (always) a carriage return and line feed. That is, in another [more complicated] manner of speaking, package your data with a \r\n between every 75 characters (treating =$$ as a unit) except, if you're encoding data that is text, you don't escape your new line bytes, and the counting starts from zero after a textual new line.

Simple, right? Either/or check for byte values with a line length check.

public static string ToQuotedPrintable(this string self)
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(self);
    StringBuilder sbInner = new StringBuilder();
    StringBuilder sbOuter = new StringBuilder();

    foreach (byte byt in bytes)
        int charLenQP = (byt >= 33 && byt <= 126 && byt != 61) ? 1 : 3;
        if (sbInner.Length + charLenQP > 75)
            sbOuter.Append(sbInner + "=\r\n");
            sbInner = new StringBuilder();

        if (1 == charLenQP)
            sbInner.Append("=" + byt.ToString("X2"));
    return sbOuter.ToString();

I think that's right.

QUICK NOTE: I am encoding in UTF-8 every time right now. You could take that in as a parameter (maybe with a UTF-8 default), but the best case would be to send in a byte array from the start, which would let you decide your own encoding, but then we couldn't use it as a fancy string extension. Though perhaps it should be a byte array extension, eh? That might make more sense.

Labels: , , ,

posted by ruffin at 1/17/2015 10:00:00 PM

Jared Sinclair responds to Marco Arment's Overcast sales numbers, and essentially says what I said in "Your App's Not Marco's", but gets a little closer to putting a number of what Marco's "Most Valuable Geek" (I read something like that somewhere else -- can't find it now -- but the intent was to say that there's a community of Apple coders that have a certain social cache. It's true, and it's A Good Thing. Who wouldn't want to get Gruber, _David, and Marco in a room to talk Apple? Maybe Gruber separately...) status buys him. Emphasis is mine.

His list of expenses leave out one really big thing: marketing. Through hard work and good fortune, Marco is a well-known figure among many of Overcast’s potential customers. This kind of exposure would be expensive for the average indie developer to replicate. For example, ongoing discussions of Overcast on the ATP podcast (before, during, and after the 1.0 launched [sic -mfn]) would have cost thousands of dollars — at least $3750 per episode. ... Promoted tweets that reach 78,000 interested Twitter followers wouldn’t be cheap, either, relative to $160K in revenue. Overcast also benefitted from numerous conversational mentions from friends of Marco’s like John Gruber, who carry a lot of weight behind their recommendations.

That's a great point -- Marco has built enough "good will inertia" (sequel to Damon & Affleck's flick) that he can "advertise disproportionally" (my words) for $160k of revenue. That's a good point.

But, admittedly, as I read, Jared's full post sounded a lot like sour grapes, which is too bad. He admits as much, but I'm ultimately not sure he understands how apples to oranges Unread is to Overcast.

Perhaps Marco intentionally left out these things because he was worried about sounding like a jerk. I’m having a hard enough time writing this article as a third-party without sounding like a [punk], so I can appreciate the backlash he might endure if he mentioned them directly.

Look, Marco's earned the "free" advertising. The difference is that his advertising is a residual, not a capital expense. He's partially living (and I know he hates this suggestion, but he can't live in a vacuum; people like him) off the interest of the work he already accomplished. Marco's socially rich in the Apple community in a way a new app developer can't be.

There's no reason to think him mentioning his social richness would make him sound a like a jerk. "Admittedly, I have a number of 'innate' advantages when it comes to advertising, not least of which is the time it got on ATP. I can't say I feel badly about that, but it is an advantage..." No problems by me. It is curious he leaves the help he's gotten from his friends and community out, to the point he's at the very least not explicitly mentioning them, but we can't expect to have a career's worth of goodwill starting from square one.

More importantly, as I said earlier, Unread is not Overcast. Even within its target technology (RSS), Unread's not a mass market app. That's not really controversial. Jared says as much constantly, and goes so far as to use "comfortable reading" (iirc) in his marketing as his killer feature. "Don't triage RSS feeds, enjoy them," was the feel I got.

Guess what? It turned out that I don't want to read slowly and carefully when I'm consuming RSS (unless it's for Medium). I want to triage and skim and consume like crazy. I bought Unread. I liked Unread. But it's no longer on my iPhone.

Overcast does everything Downcast did, but with a slightly nicer interface, that Smart Speed (catchy, no? See?) feature where I don't waste time listening to silence (listening time is my scarce resource; I'm already listening at nearly 2x speed), and it even syncs beautifully when you log in on another device. Overcast is as good in conventional use cases as what came before it, and then, in a few key ways, better. As the designer of the failed .Mail app says, "[W]e need to deliver a[...] client that works at least just as good as [popular clients], otherwise it would be a step backwards. We just can't deliver something that isn't running at least at the same performance as the examples I mentioned above." Unread tries not to match the status quo. That's not wrong, but it's risky. So don't tell me a lot of Marco's success didn't come from a more successful market positioning. His app, I think, turns out to be conventionally competitive, and, in non-destructive ways, better.

My question, and ultimately probably Jared's too, if he gives it more thought, is what I would have had to do if I'd written Overcast instead of Marco to get the same success. That's an interesting thought experiment.

Labels: , , ,

posted by ruffin at 1/17/2015 10:15:00 AM
Friday, January 16, 2015

If I'm reading this right, Apple had to pay damages because it had secure p2p video connections </ full stop>.

VirnetX had alleged that two of its patents - registered in 2002 and 2009 - had been infringed by Apple's iPhones, iPod Touches and iPads.

These referred to ways to establishing a secure communication link between different types of computers using a protocol referred to as TARP (Tunneled Agile Routing Protocol). ... "Apple says they don't infringe, but Apple developers testified that they didn't pay any attention to anyone's patents when developing their system," a lawyer for VirnetX was quoted as saying by the Bloomberg news agency.

from here:

The VirnetX patents cover the use of a domain-name service to set up virtual private networks, through which a website owner can interact with customers in a secure way or an employee can work at home and get access to a company's electronic files.

Look, if you can invent the same thing without having any idea the other existed, I'd say you haven't [in any society run by common sense] run afoul of a patent. And unless this predated Gnutella (it doesn't, I don't believe), you've got prior art, right?

Apparently some of the decision was "vacated", but I think we can agree the patent system isn't optimal. I hate that I can't even understand the argument after reading two articles. When the crux of the issue is this obfuscated, you're just playing what Gygax called (iirc) "semantic gymnastics" at this point.

Patents in software drive me crazy. Too much is painfully obvious. I understanding protecting something limited and genuinely new, but this is insane.

(sourced from reddit)

PS -- Manatees? Sauce:

Cartman is introduced to the Family Guy writing staff, who turn out to be a group of manatees. The staff, who live in a large tank, pick up "idea balls" from a large pile of them, each of which has a different noun, a verb or a pop culture reference written on it, and deliver them, five at a time, to a machine that then forms a Family Guy cutaway gag based on those ideas.

Labels: , ,

posted by ruffin at 1/16/2015 02:49:00 PM

Marco Arment very helpfully released Overcast’s 2014 sales numbers:

$164,134 total revenue after Apple’s 30% but before any taxes or expenses.

The question for me is if we can really buy Marco's "take home":

For most people, the App Store won’t be a lottery windfall, but making a decent living is within reach for many.

It's difficult to jive his numbers with a fantasy-land where he doesn't write Overcast and you write exactly the same app instead. There is a natural advantage for him when it comes to marketing, because he has your ear. I can't recall what the Accidental Tech Podcast's numbers are (where Marco is a co-host), but it's easy to see that his blog has 23,000 readers on Feedly alone.
For comparison, Daring Fireball, a blog that also cites Marco with some frequency, currently has 105k on Feedly. That cuts both ways -- to show you how big 23k is, and to show you that Arment's app has a heck of a broad broadcast reach. Even if we pretend that everyone subscribed to Marco's feed is on Daring Fireball's, and even if we pretend 20% of those are duplicate or dead subscriptions, once you add non-Feedly subscribers back in, I bet you're still over 100k high-tech, Apple-using schmoes know about his app out of the gate.

And that bears out -- he gives you the numbers if you can open the calculator or have paper handy. August through December downloads are 139,760 total, and he's had 318,996 total downloads, so he had 179,236 downloads the first month. Let's call those "launch hype" (that's a good thing to have; no derogatory connotation on "hype" here) downloads.

It had a perfect launch that far exceeded my expectations — it was the best launch an indie developer could possibly hope for, with tons of great press, a mid-level App Store feature, and thousands of tweets on launch day.

<envy />

I don't think an unknown could get that kine a launch. I just don't. I hope I'm wrong, but man, that'd take some hustling. I don't think Sinclair gave out downloads for Unread in his now famous post, and his numbers are a little wack b/c I believe he changed prices at one point (EDIT: Looks like about 2700 [obviously paid] downloads at launch at $3 each), and Unread is a paid app that doesn't play into the freemium model Overcast uses, largely because Unread is a new "experience" for RSS, not a solid-but-conventional RSS reader with a few killer features (which means Unread is not, I should say, playing into what I bet the formula to development success is).

If I was going to be blunt, I also don't think Unread has quite as much market appeal as Overcast. Overcast has some serious bugs -- I've had it display many and even download one latest podcast from feeds I've listened to and am not actively subscribed (no response yet from -- but it's arguably a better podcast app bar none than, say, Downcast. I stopped using Unread a few months after I purchased. Even in the non-IAP state, Overcast is a pretty good app. I had to have faster playback speeds, so I shelled out the cash. It hasn't given me a reason to stop using it yet.

That makes Unread to Overcast as apples to oranges, which stinks, because if Marco has years of marketing build-up behind him, Jared marks, I think, high-water for self-promotion from zero. It's like what the Unicorn Free people keep saying (and proving): If you have a huge email list, success follows. Give people something to be excited about, make them feel like part of a community, and you'll have sustainable success.

But 179k downloads your first month, with a sustained conversion rate of over 14%? You're not getting that without a heck of a lot of marketing. Even if you had the same app quality, you're going to be hustling like Jared or more to sniff those numbers.

I just wish I knew how important that huge launch and sustained chatter (look, Marco posts sales numbers! Oh yeah, we remember that app. Let's try it again! Sales bump time!) is to keeping the long tail of your sales curve taller.

Labels: , , ,

posted by ruffin at 1/16/2015 07:58:00 AM

Support freedom
All posts can be accessed here:

Just the last year o' posts:

Powered by Blogger