Mac Oil Price Widget, Version 2.0 released

By · Published · apple, dashboard widgets, dashcode, mac, osx

After a far longer wait than was intended, the Mac Oil Price Widget version 2.0 has been released.

It was completely rewritten – like, I didn’t even look at the old code – and uses Bloomberg Energy as it’s information source. The display was also simplified – I really didn’t care about the chart in the old version, so the new version prominently displays the price and how much it’s changed.

Download Here!


dystill 0.2.1 released

By · Published · dystill, e-mail, python

Just a little announcement about a maintenance release to dystill. 0.2.1 has been released, which brings with it a couple of bugfixes for issues I ran into recently. First, it will now optionally try to create new maildirs when they don't exist (this is configurable in the config file). There's also some more error checking to hopefully prevent crazy behavior.

As always, the source is on github.


PHP, methods, functions, and the global scope

By · Published · php

It's funny. Even after nearly 10 years with the language, there are still little gotchas that sometimes get me. I ran across one today.

Say you have two objects, and the look like this:

<?php
class ObjA {
    public static function test() {
        global $test;
        var_dump($test);
    }
}

class ObjB {
    public static function test() {
        $test = 1;
        ObjA::test();
    }
}

ObjB::test();
?>

It doesn't work. You get NULL.

Say I were to do something like this:

<?php 
class ObjB {
 public static function test() {
     $test = 1;
     global $test;
     var_dump($test);
 }
}

ObjB::test();
?>

You also get NULL. And this:

<?php 
function a() {
    $test = 1;
    b();
}

function b() {
    global $test;
    var_dump($test);
}

a();
?>

Also fails.

The reason is that the global scope on PHP is just that: global. Any time you're in a function or method, you're in a local scope and all local scopes are independent of each other. So you can't global in something from one local scope to another. Variables are either global or local.

That much I get and makes sense (and is in the documentation). What threw me for a loop was that PHP won't copy something into the global scope from a local scope that is already defined *and will happily overwrite your local scope with a null value from the global scope if one doesn't exist in the global scope, *in the process of creating the variable in the global scope. If you want a variable in the local scope to be global, you have to declare it as global before you write a value to it.

Or, to put it another way:

<?php 
class ObjA {
    public static function test() {
        global $test;
        var_dump($test);
    }
}

class ObjB {
    public static function test() {
        global $test;
        $test = 1;
        ObjA::test();
    }
}

ObjB::test();
?>

Works beautifully.


App Store Entitlements, and the Crippling of an App

By · Published · apple, objective-c, xcode, mac, osx

A few months ago, I decided I wanted to try exploring the Mac App Store ecosystem as a developer. I've been writing little Objective-C apps for myself for awhile, and I decided I wanted to see what it was like from the other side.

So I wrote this little app called Airplane Setting. It was a stupid simple little app that made it easy to turn off your radios with a single action. I wrote the app and paid my $99 admission fee. And after a month of back and fourth with Apple and a couple of rejections for what I consider to be dubious reasons as best (especially seeing as how I could point out existing apps in the store that broke the "rule" they said my app was breaking, but whatever, their store, their rules...), my little App was finally approved for sale. It did moderately well, passing 1,000 downloads with virtually no advertising from me.

I had big dreams for this little app. Plugins, global hotkey support, localization, Applescript support, and more potential functionality. But all that was dashed by "Entitlements" and Apple's requirement that all apps must be sandboxed.

Look, in theory, the idea of sandboxing an app is not bad. The problem here is Apple's all-or-nothing approach to sandboxing. The selection of entitlements are just so limited as to be nearly useless for anyone creating a unique, new or complex app - especially one that requires hardware access. Your choice is either to sandbox your app, choosing from the available selection of entitlements, or not sandbox it and not be in the Mac App Store at all starting in March. There's no reason to only provide such a limited subset of functionality that a developer must choose from. Would it not be better to provide us a wider set of entitlements and allow us to justify our reasons for needing them when we submit our app?

The reason Apple gives for requiring sandboxing is to prevent "rogue apps" from destabilizing the system. But when you consider that the App Store itself is curated, this requirement makes even less sense. If Apple is curating the store, how does a "rogue app" end up in the App Store?

I'm a huge Apple fanboy. I have almost all Apple hardware in my house, from my iMac to my Macbook Pros, to my iPad and iPhone and my wife's iPod Touch. I had AppleTVs before they were cool (and there's one on every one of my TVs now). I love Apple. But as an developer ... I [expletive] hate Apple for this "innovation" that crippled my once-promising little app.

So, at this point, my options are:

  1. Leave Airplane Setting in the App Store. Doing so will mean no further updates so I'll likely cease development.

  2. Remove Airplane Setting from the App Store and start distributing it exclusively from the website.

My original intent with Airplane Setting was to explore what it was like to be an App Store developer. I guess ... now I know what it's like to be an App Store developer, and living in constant fear of Apple as a sword of damocles hanging over your head.


Goodbye GoDaddy

By · Published · news, ramblings

Using GoDaddy as my registrar is one of those things I've always felt vaguely ashamed of. Something I knew all the "cool kids" didn't do, but I was already so neck-deep in them that I didn't want to transfer. Not to mention I had my DNS hosted with them as well so the thought of going through all that trouble to move just seemed like too much of a hassle to deal with without good reason.

In my last entry, I talked about setting up your own DNS server. This was the first part of my attack on moving my domains away from GoDaddy. But I didn't have a real timeline to move away from them.

Then came the news of GoDaddy's support for SOPA - one of the worst attacks on the Internet since 1996's Communications Decency Act.

Now, to be sure, GoDaddy's position on SOPA was not the first thing they've done to anger me. Their overtly misogynistic advertising has always bothered me, and their CEO Bob Parsons' elephant killing and shameless exploitation of the natives angered me so badly that I almost left in April. But their aggressive support of SOPA was the final straw for me. I'd been a customer since 2003, but I simply could not take it anymore.

So over the course of about 4 days, I transferred all my domains to Namecheap. Having never transferred a domain before, the process was surprisingly quick and easy. Once again, it makes me wonder why I haven't done it sooner.


The Stupid Simple Guide to Setting Up Your Own DNS Server

By · Published · linux, networking

I'm a developer, first and foremost. I like writing code. To me, maintaining servers, configuring things, troubleshooting network issues and the like -  these are things I do to support my primary interest and job as a developer. I'm not ignorant of these things, but all things considered they're not my favorite things to do.

One thing I will admit I've been ignorant over the years is DNS. Oh sure, I know at a high level how it works. I even know a bit about the different record types. I knew enough to have my own domain name, configured using Godaddy's DNS servers to point to my server. But actually running my own name server? Something I've never done and, for some reason, had this unnatural fear of.

Well, no more. I'm now running my very own shiny new name server and, actually, it wasn't really as difficult as I thought. And because this was a learning experience for me, I figured I'd walk you through what I did as well.

Picking  a Server

There are two big players in the "DNS Server software" space: BIND and djbdns. BIND is the 900 pound gorilla that has been around forever and ever, and is insanely difficult to configure. djbdns is from the same guy who wrote qmail - I'll let you be the judge of that. But after researching and actually attempting to install both of these, I eventually gave up. Both just came across as being too complex for a simple name server handling a couple of domains, and the documentation for both was equally complex.

That's when someone on Twitter pointed me to MaraDNS. I looked it over and was surprised to find good, readable and simple documentation that made it look easy to install. So I decided to give it a whirl. Here's what I did. Note that this install is for a Gentoo system. Yours will be different if you're using something else.

Installing and Configuring MaraDNS

First step is to install it.

emerge maradns

And let Portage do its thing. Once it's installed, you really only have to worry about a few files. In /etc/mararc, you need to check to be sure you're binding to the right interfaces. In my config, I bound it to the loopback and to the main interface:

ipv4_bind_addresses = "x.x.x.x, 127.0.0."

After that, you tell it to be authoritative, and what domains you are wanting to serve records for.

csv2 = {}
csv2["robpeck.com."] = "zones/robpeck.com"

Note the period at the end of the domain name - it's important. Each entry in the csv2 array should map to a zone file. I put mine in the "zones" subdirectory (which, in Gentoo, lives under /etc/maradns).

mkdir -p /etc/maradns/zones

Then, with your favorite editor (which should be vi :P), you create your zone file. The one for robpeck.com (partially) looks like this:

robpeck.com.       NS ns1.epsilonthree.com.
robpeck.com.       NS ns2.epsilonthree.com.
robpeck.com. +3600 A x.x.x.x
robpeck.com. +3600 MX 0 robpeck.com.

www.robpeck.com. +3600 CNAME robpeck.com.

So what are we doing here? Well, here it helps to know something about the different types of DNS records. I'm not going to cover all the different types of records - this is a good list of common ones and Wikipedia has a full list. The important ones you need to know are NS (Name Server), A (the main record), MX (mail server records), and CNAME (alias). The "+3600" is setting a timeout on the records to one hour (3,600 seconds). By default, the server will send one day (86,400 seconds).

Here, I'm telling the server what the name servers are (strictly speaking, this isn't required, but I added it all the same) and that the main address for people requesting "robpeck.com" is this IP address. I'm also saying that people who request "www.robpeck.com" should get the IP address for "robpeck.com." I also add an MX record that points to robpeck.com with 0 as the priority (the first (and only) server).

That's it! Restart MaraDNS:

/etc/init.d/maradns restart

And you can test it out.

dig @localhost robpeck.com A

You should get a big long printout, but what you want to see is these two lines:

QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 0
robpeck.com. 3600 IN A x.x.x.x

Assuming the above is the correct address, congratulations, your DNS server is now resolving properly locally.

Delegating your Domain

The next step is delegating your domain to your own server. I'm not going to cover this in too much detail because how it happens depends on the registrar. In general, this is a two step process:

  1. Register your name server's IP address to a name. At NameCheap, when you're in the domain screen this is done under Advanced Options > Nameserver Registration. Under GoDaddy, this is under the "Hosts" section of the domain information screen. You need to add at least two "nsX.domain.com" entries, but they can both point to the same IP.

  2. Delegate your domain to the names you just created. At NameCheap, you would go General > Domain Name Server setup, and Specify Custom DNS Servers. Then, enter the two (or more) names you just created "nsX.domain.com". I can't remember how I did this in GoDaddy, but I remember it was pretty apparent.

That's it! They say it takes 24-48 hours, but I started seeing requests hit the new name server within about an hour. Of course, since I wasn't actually changing IP addresses, there was no real downtime.

As of now, all my domains are being served off my own nameserver. It's kind of a neat feeling of accomplishment, knowing you're not relying on someone else's DNS setup - they're just providing you a name. This makes domain transferring much easier and adding new records much easier. And seeing as how I'm currently in the process of transferring all my domains away from GoDaddy, this will ease the transition.


Goodbye, Eclipse.

By · Published · apple, pc, php, windows, mac, osx

Dear Eclipse,

We've known each other a long time, haven't we? I remember when we first met. It was way back in 2005, two jobs ago when I was working at interactive Point of View. I was still a young, naive kid, just out of college. At the time I was just getting my start writing serious PHP code, and you were a breath of fresh air compared to what I had been using before (Dreamweaver). You seduced me with your awesome power and functionality.

I used to love being able to have code on top and a browser window underneath. Ironically enough, one of my favorite features would eventually be something I couldn't care the slightest about.

Later that year I would move on to Asteria, and I took you with me. This was the first time I had two monitors on my desk, and I kept Eclipse in one, and a browser in the other while programming. Again, your raw power made complex tasks easy. I discovered Subversion integration, which made Tortoise (I was still on Windows at the time) irrelevant to me. Your Subversion tools turned me into a huge fan.

When I moved jobs again, to dealnews, I again took you with me. Much to the chagrin of my coworkers, I preached the gospel of Eclipse. When I first started I was still in the Windows environment and my setup was much like it was at Asteria. Later that year when I switched to Mac, I again took you with me. You occupied a place of honor in my dock.

We upgraded together. Through Callisto, Europa, Ganymede, Galileo, Helios and Indigo. We upgraded through Leopard, Snow Leopard and Lion together.

Sure, we had our occasional disagreements and outright fights. I remember one time when you would absolutely choke on the size of dealnews' code tree. I would try other editors and IDEs. I tried jEdit, Coda and TextMate. But I always came back to you.

But all things change, and this time I think we're finally through together.

The first sign you were no longer interested in me was the dropping of the official PHP build - the one I had been using for years. But you knew I was worried - you even said so on your website and pointed me to PDT - PHP Development Tools. This aphrodisiac, you told me, would make our relationship just like we were kids again.

But what you didn't tell me was that PDT would make you crazy and unstable in the worst kind of way. Your behavior has become increasingly erratic whenever you take PDT. You developed bugs, including ones that I could no longer justify. Ones that were literally costing me time every day. You said PDT could auto-complete code and when it does it works great. But when it doesn't, the display glitches up the file so badly that the only way to get back into a usable state is to close the file and reopen. Now imagine doing this four or five times for every file you're editing, every time you try to auto-complete some HTML. Your ill tempered behavior is costing me time and money.

I tried to talk with you about it, but all you could say was NullPointerException.

So, I've thought a lot about this. It's been a good six year run, but I think it's time we ended our relationship together.

The truth is that I know about your other boyfriend, too. I know his name is Android, and I know you guys have been spending a lot of time together. And I'm okay with it. Really. All things change and we all have to adapt. The truth is I've been fooling around some with your cousin Netbeans, and I think we're really hitting it off. In many ways, she reminds me of you. The difference is, Netbeans has herself together, is trying hard to improve herself and hasn't forgotten who her friends are, instead of getting strung out on PDT and spending all her time hanging out in the backseat of Android's Pinto.

So goodbye, Eclipse. What we had was wonderful while it lasted and I'll always treasure our time together and the memories we made. I hope your new life works out. Maybe we'll see each other from time to time, but I honestly I don't think that would be fair to Netbeans. She's my new IDE now.

-Rob Peck Eclipse User, 2005-2011



Mac Oil Price Widget

By · Published · apple, dashboard widgets, dashcode, mac, osx

Because there doesn’t seem to be a good, simple way to track oil prices on the Mac dashboard anymore since the previous widget I used quit working, I whipped up a quick little widget that allows me to monitor the price of Crude Oil on the New York Mercantile Exchange.

You can download it over on its own page.


PHP Filtering: Validation, Sanitizing and Flags

By · Published · php

PHP's filter functions are really, really great. I've started using them almost any time I need to get input from a user and, personally, I don't think you should use the old $GET, $POST unless you know what you are doing and there is some specific thing you're trying to accomplish that you can't with filter. Filter forces you to think carefully about what inputs your script takes and what format it takes them in.

But there are also some behaviors of filter that can bite you in the rear if you aren't really careful. One of these is knowing which flags you need to pass and what the difference between validation and sanitizing, when is the right time to  use each, and what flags to use. I ran into a good example of this today where I messed it up.

I had configured filterinputarray to pull in a variable as FILTERVALIDATEFLOAT, probably because I wasn't thinking like a user and instead was thinking like a developer. I'm the type of person that, when a form wants to know my phone number, I only enter 10 digits without parentheses or dashes. But users are different. They like friendly things. In this case, the user was entering "16,473.54" and the like into that box.

Now, I can look at that and say, "yeah, that's a float" (actually, it's currency). It should be considered a valid value. But FILTERVALIDATEFLOAT will throw this out because it has a comma in it, unless you pass FILTERFLAGALLOW_THOUSAND. Then, and only then, does it return the above as a valid value (in this case "16473.54").

But I looked at the code again. In this case, the value doesn't need to be there except in a specific case, which I handled in error checking in the code, so I switched it to a Sanitize value instead. It's probably a good idea to only use  FILTERVALIDATE* functions when your user has to give you a valid value and your script would fail if that wasn't the case. If a validation returns false, you should fail the process and return a (nice) error message to the user. Sanitize functions allow you to accept a little wider range of data and still return a valid value from it. The docs have a great example of this involving email addresses.

So if you're writing PHP these days, definitely use filter. Just be careful and mind the flags and the difference between validation and sanitizing.