Blogs

Prompt PayPal payment processing, part 3

Here's the remainder of the PHP code for the recent automation of my PayPal-based store, using PayPal's Instant Payment Notification (IPN) service. See part 1 for the introduction and part 2 for the start of the code.

So now we've got a valid transaction, so can begin to process it. As I previously said, I use a shopping cart, so I need to loop over the cart contents. I call the getPayPalShoppingCartValue() function (provided in part 2) to get values specific to a product; shared values can be copied easily. This should all work without a shopping cart, too. I save the values into a $license associative array, which is equivalent to a Cocoa NSDictionary.

    $count = $transaction['num_cart_items'];
   
    if ($count < 1)
        $count = 1;
   
    // Process each shopping cart item as a separate license:
    for ($index = 0; $index < $count; $index++)
    {
        // Construct the license:
        $license = array();
       
        $license['Parser'] = 'PayPal';
        $license['Parameters'] = $transaction;
        $license['Name'] = $transaction['first_name'] . " " . $transaction['last_name'];
        $license['Email'] = $transaction['payer_email'];
        $license['Postal'] = $transaction['address_street'] . ", " . $transaction['address_city'] . ", ";
        $license['Postal'] .= $transaction['address_state'] . " " . $transaction['address_zip'] . ", " . $transaction['address_country'];
        $license['PaymentAmount'] = getPayPalShoppingCartValue($transaction, 'mc_gross', $index);
        $license['TotalAmount'] = $transaction['mc_gross'];
        $license['Quantity'] = getPayPalShoppingCartValue($transaction, 'quantity', $index);
        $license['ProcessorNote'] = $transaction['payment_date'];
        $license['ProcessorTransID'] = $transaction['txn_id'];
        $license['ProcessorName'] = 'PayPal';
        $license['PaymentMethod'] = 'PayPal';
       
        $ref = getPayPalShoppingCartValue($transaction, 'option_selection1', $index);
       
        if (!$ref)
            $ref = 'paypal';
       
        $license['Referrer'] = $ref;
        $license['Special'] = getPayPalShoppingCartValue($transaction, 'option_selection2', $index);
       
        if ($testMode)
            $license['Test'] = 1;
       
        $license['ServerReferrer'] = $_SERVER['HTTP_REFERER'];
        $license['ServerIP'] = $_SERVER['REMOTE_ADDR'];
        $license['ServerAgent'] = $_SERVER['HTTP_USER_AGENT'];
       
        $itemName = getPayPalShoppingCartValue($transaction, 'item_name', $index);
        $isDonation = strcontains($itemName, 'Donation', true);
       
        setLicenseProduct($license, $itemName);

The setLicenseProduct() function simply maps the shopping cart's item name to my own product identifier.

Time to actually add the license. This is done with another function to be left as an exercise for the reader, addLicense(). It takes the $license array we just constructed, adds it to the license database, and returns (by reference) any error. If the sale was a donation for a freeware product or a pending sale, though, the add is bypassed, since a donation doesn't need a license, and a pending sale (if it reaches here) shouldn't be issued one.

We then construct an email to the customer, with different wording for freeware, pending, or normal sales. I'm omitting most of that, since it's specific to your situation:

        // Add the license, unless it's a donation or pending:
        if ($isDonation || $isPending || addLicense($license, $error))
        {
            $productName = $license['ProductName'];
            $version = $license['Version'];
            $name = $license['Name'];
            $email = $license['Email'];
           
            // Donations and pending transactions will use the item name for the product name,
            // as the latter is set in updateLicense(), which isn't called for them:
            if (!$productName)
                $productName = $itemName;
           
            if ($isDonation)
                $body = "Greetings.  Thank you for the $productName!  I appreciate it.\n\n\n";
            else if ($isPending)
            {
                $body = "Greetings.  Thank you for purchasing a $productName.\n\n\n";
                $body .= "Your PayPal transaction is still pending, so you will receive your license when the payment is complete.\n\n\n";
            }
            else
            {
                $body = "Greetings.  Thank you for purchasing $productName.\n\n\n";
                $body .= "Licensed Name: $name\n";
                $body .= "Licensed Email: $email\n";
                $body .= "License Kind: " . $license['KindName'] . "\n";
                $body .= "$productName $version Serial Number: " . $license['Serial'] . "\n\n\n";
                // Instructions on adding the license omitted...
            }
           
            // Info on forums, FAQ, email contacts, etc omitted...
           
            $headers = "From: MyCompany <sales@mycompany.com>\r\n";
            $headers .= "Bcc: MyCompany <sales@mycompany.com>\r\n";
            $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
           
            if ($isDonation)
                $subject = $productName;
            else if ($isPending)
                $subject = "$productName purchase";
            else
                $subject = "$productName license";
           
            mail("$name <$email>", $subject, $body, $headers);
        }
        else if ($error)
            exitWithError('PayPal', $error, $license);
    }
   
    header("Content-Type: text/text");
    echo("Transaction completed.");
}

And we're done! I hope this is helpful. This all seems to work fine for me, but if you spot any bugs or have any suggestions for improvements, please let me know. If you have any questions, I'd be happy to elaborate more. I'd be keen to hear from people who use this code, too.

Prompt PayPal payment processing, part 2

As discussed in part 1, I recently automated my PayPal-based store, using PayPal's Instant Payment Notification (IPN) service.

For those interested in the technical details, perhaps implementing this for your own store, here's my code. This is written in PHP, but other languages can be used too.

Firstly, a couple of utility functions. For getPayPalShoppingCartValue(), given the PayPal transaction data, a key, and the (zero-based) index, this returns the corresponding value. Tries the key with the index appended, with an underscore and the index appended, or by itself; the documentation is somewhat inconsistent on how it is applied, though I think an underscore is usually used. All this code should still work fine if you aren't using the shopping cart, too.

function getPayPalShoppingCartValue(&$transaction, $key, $index = 0)
{
    $value = $transaction[$key . ($index + 1)];
   
    if (!$value)
        $value = $transaction[$key . '_' . ($index + 1)];
   
    if (!$value)
        $value = $transaction[$key];
   
    return $value;
}

Next, the exitWithError() function emails me the details of an error, for diagnostic purposes, then exits the script. You can optionally pass an array and it will be included in the email. It also outputs the error (normally wouldn't be seen). It calls another existing function of mine (not provided here) that returns the array as an ASCII property list; there are other ways to output it too. Of course, you should replace the mycompany.com email addresses with your own.

function exitWithError($parser, $error = '', $array = null)
{
    $body = "An error occurred with the $parser parser:\n\n$error\n\n";
   
    if ($array)
        $body .= arrayToASCIIPropertyList($array);
   
    $headers = "From: MyCompany <info@mycompany.com>\r\n";
    $headers .= "X-Mailer: PHP/" . phpversion() . "\r\n";
   
    mail("info@mycompany.com", "Store error: $error", $body, $headers);
   
    header("Content-Type: text/text");
    echo("$parser error: $error");
   
    exit();
}

On to the main code. I actually have this in a function in my code, as it is just one processor function among others, but if you only have one, it can be at the top level of the script.

function handlePayPal()
{
    // Copy to a local variable for convenience, and since the post back to PayPal might wipe it:
    $transaction = $_POST;
   
    // Test mode is activated by passing test=1 to my PayPal Store.  It then uses PayPal's sandbox site instead:
    $testMode = $transaction['test_ipn'] == 1;
   
    if ($testMode)
    {
        mail("MyCompany <sales@mycompany.com>", "PayPal IPN starting", arrayToASCIIPropertyList($transaction), "From: MyCompany <sales@mycompany.com>\r\n");
       
        $paypalDomain = 'www.sandbox.paypal.com';
        $receiverEmail = 'paypal_sandbox_biz@mycompany.com';
    }
    else
    {
        $paypalDomain = 'www.paypal.com';
        $receiverEmail = 'paypal@mycompany.com';
    }

The above sets up things based on whether the purchase was via the PayPal sandbox or your live store. The sandbox is a great way to create fake customer and seller accounts for testing without spending real money. You can initiate this test mode by changing the action on your form from <https://www.paypal.com/cgi-bin/webscr> to <https://www.sandbox.paypal.com/cgi-bin/webscr>. You also need to change the form's "business" field to the sandbox receiver email address.

Next up, we post the received data back to PayPal, so they can confirm that they actually sent it. We construct and post urlencoded form data to their server, then fetch the response. If it's VERIFIED, we're good:

    // Read the post from PayPal system and add 'cmd':
    $req = 'cmd=_notify-validate';
   
    foreach ($_POST as $key => $value)
    {
        $value = urlencode(stripslashes($value));
        $req .= "&$key=$value";
    }
   
    // Post back to PayPal system to validate:
    $header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
    $header .= "Host: $paypalDomain:80\r\n";
    $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
   
    $fp = fsockopen($paypalDomain, 80, $errno, $errstr, 30);
   
    if (!$fp)
        exitWithError('PayPal', 'Unable to connect to the PayPal server.', $transaction);
   
    fputs($fp, $header . $req);
   
    $verified = false;
   
    // Read the response:
    while (!feof($fp))
    {
        $line = fgets($fp, 1024);
       
        if (strcmp($line, "VERIFIED") == 0)
            $verified = true;
    }
   
    fclose($fp);
   
    // Ensure PayPal verified the post:
    if (!$verified)
        exitWithError('PayPal', 'Received a transaction that PayPal did not verify as valid.', $transaction);

We then do some further checks, to ensure the payment went to the correct address, and the transaction has an acceptable status. I wrote this before realizing that pending transactions probably don't reach this point anyway (I think PayPal holds off notifying till they are completed), but it doesn't hurt to leave the pending logic in here:

    // Ensure the payment went to me:
    if ($transaction['receiver_email'] != $receiverEmail)
        exitWithError('PayPal', 'The receiver email was not correct.', $transaction);
   
    $transStatus = $transaction['payment_status'];
    $isPending = ($transStatus == 'Pending');
   
    if (!$isPending && $transStatus != 'Completed')
        exitWithError('PayPal', "The transaction status was $transStatus.", $transaction);

So now we've got a valid transaction, so can begin to process it. Continue to part 3 with the remainder of the code!

Time Out 1.5 released

Time Out version 1.5 is now in general release. It includes an improved icon (as seen on the Dejal site for a few months), a rearranged break layout, and the ability to change the postpone button intervals, or hide either of them and/or the skip break button, if desired. Plus some other minor changes and fixes. See the release notes and the blog entry on the beta release for more information.

Time Out 1.5 is freeware; you are welcome to use it at no cost. However, donations to support development of version 2 are always appreciated... and since I've announced version 2, everyone who donates (any amount!) will be eligible for a Time Out 2 license at no further cost. This offer will expire when Time Out 2 is released (after Leopard).

Download Time Out 1.5 now!

Prompt PayPal payment processing, part 1

I use two payment processors for Dejal: Kagi and PayPal. The Dejal Store powered by Kagi has been fully automated for years, so when a customer buys one of my products, Kagi queries my server, which generates a serial number and passes it back to Kagi's server, and the customer receives it automatically as part of Kagi's "Thanks for your purchase" message. This is very convenient for both me and the customer. (My products also include a Kagi-based store right within the app, which avoids the need to even enter the serial number.)

For the Dejal Store powered by PayPal, on the other hand, it has been a manual process. When someone purchased via PayPal, I received a notification of the payment in my email, which I copied to my home-grown license management app, which parsed it to generate the license, including creating an email message in Mail ready to send. This wasn't much work, but required manual processing on my part, which of course meant the customer had to wait for me before they got their license. I was usually very prompt, but if they bought while I was asleep or otherwise away from my machine, they had to wait. That's just not great service.

So this week I've spent the time to automate the PayPal processing. Now, if you buy from my PayPal store, PayPal will send my server a notification with the shopping cart contents. My server will then automatically add licenses and generate and send out email messages for each product purchased. So now purchasing from either store (or within the app) will give you your license details virtually immediately, with no need for waiting for me. Which of course means less work for me, too, so I can spend more time answering support questions or writing code.

Getting technical

Implementing the PayPal automation wasn't too difficult, though it took some research to find the best solutions. For the standard PayPal business accounts, they offer two automated payment notification services: Payment Data Transfer (PDT) and Instant Payment Notification (IPN). My initial research showed people using PDT, for example that's what the AquaticPrime framework uses. However, further research showed that this might not be the best choice. The way it works is to send the transaction information to your server when the customer is redirected back to your website after the purchase. But if they close their browser window or click away before they return to your site, your server doesn't get the transaction info. Also, you have to deal with pending transactions (e.g. eChecks), form reloads, and other issues.

So then I switched to using IPN. This is a more robust mechanism, but still quite simple to implement. In this case, the payment notification occurs in the background, whether or not the customer actually returns to your site. I believe that pending transactions aren't received until they clear, too. So this is more reliable and efficient.

Both services include fraud protections, in the form of posting the received data back to PayPal and getting a response. If they originated the data, they'll reply saying that it was confirmed, otherwise it's suspicious.

To make things more interesting, my store pages offer multiple products for sale, so I need a shopping cart. Most existing examples assumed a single buy button, but fortunately the PayPal data copes with shopping cart transactions in a fairly simple way, appending digits to the variables.

Continue reading part 2, with a discussion of the PHP code to implement this.

Too unintentionally with continuation sinking

Something I found amusing: I noticed a mention of the Time Out 1.5b1 release on Plateaus.com, a Japanese site (via my site referrers), and auto-translated it to English using Google... admittedly a beta translator. Here's what it came up with:

When work and music are done, (with saying, as for work almost it is Windows but), too unintentionally with continuation sinking, when the air is attached, the eye and the shoulder [gakugaku] is good.

This timeout as at the time interval which is appointed shown under, putting on the thin cover in the picture, (can adjust also transparency), in order to break, you teach. In addition, the script which is executed at the time of sound and start and the end which are let flow when starting and end break (also Automator, AppleScript and the Python script) or the appointment etc of application is possible.

Standard setting is, the public official of the country whether with "micro" break in 10 minutes 10 seconds, with "usually" break in 50 minutes 10 minutes (the [do] [tsu] of is like but), but you are appointment possible by your. It is useful unexpectedly. It is the freeware.

Auto-translation is hard, eh. :)

Time Out 1.5b1 released

It's been a while since the previous version, but Time Out 1.5 is now in beta release.

As mentioned a couple of times recently, version 1.5 is an interim release for 10.3.9 and up, before the big 2.0 upgrade, coming later this year for Leopard.

I've been using the new Time Out icon on the Dejal site since January, but till now the Time Out application itself has still used the "aesthetically challenged" old icon, which consisted of a very badly Photoshopped rendering of my hands in a "T" shape. I've never liked that icon, and I've certainly got lots of feedback over the years that you don't either... so it was a priority when I got Emily Pfeifer to redesign some of my app icons (and the Dejal logo). I'm very happy with the new design, and I hope you are too.

A subtle change is the name of the application. It used to be "Time Out!", with an exclamation point at the end of the name, but I'd grown to dislike that too, what with the hassles and untidiness it caused when referring to the application. So I've dropped the exclamation point from the name.

Feature-wise, 1.5 has a rearranged break layout, with the progress bar and buttons within a box, a more elegant font and color for the "Time Out" text, and the new icon, of course. By popular request, it also includes options to remove any or all of the buttons, and to change the postpone amounts. So if you find the temptation to skip a break too strong, you can get rid of the button to encourage you to take the break. Check out the release notes for more changes.

Here's a feature graphic for Time Out 1.5b1, as seen in rotation (with ones for Simon and Caboodle currently) on the Dejal home page:

Version 1.5 may be the last version of Time Out for Mac OS X 10.3.9 and later. Version 2 and beyond will require a minimum of Mac OS X 10.5, as they will leverage several of the great technologies introduced in Leopard. I'll keep 1.5 around for the foreseeable future, for people who haven't upgraded to Leopard.

And yes, 1.5 is still completely free! While version 2 will be shareware, I am currently planning to also offer a free Lite version, which will have the same features as 1.5, plus some extras.

Product positioning ponderings

As as been mentioned before, I'm working on Time Out version 2 (in between other projects), to be released once Leopard is publicly available.

At present Time Out is freeware. It probably shouldn't be, as it's a great, very popular product, but it started that way and has remained so thus far. That will change with version 2, which will include pretty much all of the most popular features people have been asking for over the last few years, many of which I've been keen to do but couldn't justify in a free version.

So version 2 and beyond will be shareware, and require a minimum of Leopard. However, I plan to keep version 1.5 (to be released soon) around for people who haven't yet upgraded to Leopard. Version 1.5 will remain free, and for 10.3.9 and later. That could also serve as an alternative for people who don't want the improvements in version 2 (or don't want to pay for Time Out)... but I'm also considering other options.

The latest such option to ponder is having a "Lite" edition of version 2. So there would be the standard Time Out 2, a shareware product, plus Time Out Lite 2, a freeware product. The Lite edition would have basically the same feature set as version 1.5, plus a few enhancements. The standard edition would have lots more new features. If the basic features were enough for you, you could use Time Out Lite at no cost, like you can use current versions. If you want the extra features, you install the standard Time Out and buy a license. Like my other products, you could install Time Out and try the full features for a while before deciding to buy.

A previous option that I thought of was to have just one Time Out 2 app, but two or three license levels, like for Simon. Under this approach, there would be a cheap Basic license with limited features, a Standard license with advanced features, and perhaps an Enterprise or Site license with the same features but allowing company-wide installation. This is different than the above approach in that there is no separate free edition; the differentiation is all in license levels. I do like the idea of keeping a free edition, though.

Another idea was similar to that one, having more of a "seat"-based approach. One license, the same features for everyone, but quantity discounts for multiple users. This is more like the Individual/Household/Site license model that I use for Caboodle and other apps. A seat-based approach could perhaps be combined with the latest approach (of standard and Lite editions).

What do you all think? Any preferences, or other ideas? Feedback would be appreciated, via the comments, the Time Out forum, or privately.

Simon 2.3 released

Simon version 2.3 is now in general release!

As previously discussed, this release includes a new Mount plug-in, that works both as a service and notifier, and allows mounting and unmounting local, AFP, and SMB volumes. It also extends the Script plug-in to act as a notifier too, allowing great flexibility in notifications. Plus many other enhancements and fixes. See the release notes for more information, or download now!

Multi-touch on the desktop

Craig Hockenberry wrote thought-provokingly about multi-touch interfaces on the desktop (via Gus Mueller).

This is a favorite topic of mine; as I've written before, I look forward to the day when multi-touch comes to desktop (or portable) computers.

One of his objections was the vertical orientation of traditional displays:

If you’re one of the people who think that a multi-touch monitor is a good idea, try this little experiment: touch the top and bottom of your display repeatedly for five minutes. Unless you’re able to beat the governor of California in an arm wrestling match, you’ll give up well before that time limit. Now can you imagine using an interface like this for an eight hour work day?

But he quickly counters that objection with what I feel is the obvious answer: a touch-based interface needs to be at a comfortable angle. I envision a desktop multi-touch surface at a 30-degree angle, or less, from the desktop: as he says, like a classic drafting table. Perhaps there won't be a distinction between desktop and notebook computers anymore, or perhaps the computer will be in two parts: a tablet-like mobile portion, which docks into and rests on a wedge-like stand on your desk, which adds additional functionality (kinda like the old PowerBook Duo and DuoDock).

The multi-touch screen would be the entire interface (other than perhaps some auxiliary buttons like brightness, volume, etc). It would obviously replace the mouse/trackpad, but would also replace the keyboard, using an onscreen keyboard instead. Yes, tactile feedback is an issue, but as many people have reported with their iPhones, it's possible to get used to typing without it; and there are ways to provide feedback, like the iPhone's magnified view of pressed keys, sounds, vibrations, and other ideas being worked on.

Hockenberry also raises a valid point regarding the precision of a mouse pointer vs a finger:

But even if there was a solution to the ergonomic issues, there would be problems mixing mouse-based applications (with small hit areas) with touch-based inputs (and large hit areas). Touch-based UI is not something you just bolt onto existing applications—it’s something that has to be designed in from the start.

Certainly an important consideration. However I would argue that most applications could be modified to support larger hit areas in sensible ways without too much difficulty - though in some cases major redesigns would be needed. Just have a look around the controls in your favorite apps, and think about how easy it would be to "click" on one with a finger, without activating a nearby control. In most cases, controls are spaced out enough for it to not be a problem, but some, like Photoshop, would require either optional support for a stylus (which Apple probably wouldn't be in favor of), or a finer on-screen control (perhaps like the iPhone's magnifying glass). I'm sure apps designed from the ground up with multi-touch in mind would be better... but migration is certainly possible. And yes, resolution independence should help. If you've got big fingers, you just scale everything up to a comfortable level.

I really believe that multi-touch is the way of the future, and will be coming for Macs in due course. But Apple being Apple, they will do it right, with as smooth a migration path for developers and users as possible.

Time Out featured on Lifehacker

Time Out is a featured download on Lifehacker today. They seem to like it, which is always nice. Lifehacker is a great productivity blog, that I read every day, and recommend to others.

I appreciate the publicity, though I kinda wish it had come in a couple of weeks time, as (by popular request) I am planning to release Time Out version 1.5 with the new icon, and a few other improvements, around that time.

If you've come here from Lifehacker or elsewhere to get Time Out, go ahead; the current version is very good... but the icon is somewhat aesthetically challenged. So come back in a couple of weeks to get 1.5 - Time Out will tell you when it's available.

Version 1.5 will remain freeware, for Mac OS X 10.3.9 and later.

As for Time Out 2, it is still in development, but will require Leopard (Mac OS X 10.5) as a minimum, so version 1.5 will tide people over till Leopard is out (and for people who don't upgrade).

Simon 2.3b1 released

I'm pleased to announce a beta release of Simon version 2.3. This update adds a useful new Mount service and notifier, that allows you to check if a local, AFP or SMB volume is mounted, and optionally unmount it. The notifier can be used to mount or unmount a volume as a result of a check.

It also extends the Script plug-in to act as a notifier as well as service. This means that you can now write AppleScripts, shell scripts, Perl, Python, Ruby, etc scripts to do some custom action when a test fails, recovers, or changes. This is a very exciting feature, that expands Simon's already extensive flexibility by an order of magnitude. Not to belabor the hyperbole, but with the new Script notifier, the notification options are now limitless!

This release also includes some new test options, to allow customizing the timeout interval and offline checking, some handy new variables, a number of bug fixes, and compatibility with the current Leopard beta.

There are lots of other nifty enhancements in this release; see the release notes for the full list, or download now!

This is a free update for licensed Simon users.

Caboodle 1.1.2 released

Caboodle has now been updated to version 1.1.2. Similar to yesterday's updates of Macfilink and BlogAssist, this update includes minor tweaks to ensure compatibility with Leopard. It also includes some fixes for ruler handling within entries, to make the preference and menu item work better - existing entries now save the ruler visibility state properly, and new root-level entries now use the preference.

Enjoy!

Macfilink 1.4.1 & BlogAssist 2.1.1 released

Macfilink has now been updated to version 1.4.1, and BlogAssist has been updated to version 2.1.1.

These updates just include some minor changes and fixes that other apps have already received, plus some minor tweaks to ensure compatibility with Leopard, aka Mac OS X 10.5, for those running the developer beta (as I am) or to make the transition smoother when you eventually upgrade.

They are recommended updates for all Macfilink and BlogAssist users... and of course recommended apps for everyone else, too. :)

A store highlight

I've just rolled out some minor changes to the Dejal Store, to enhance the item selection. Having recently bought a new MacBook Pro, I admired how the Apple Store makes it easy to choose the options, and highlights the selected items. (If you're familiar with the way web browsers work, you'll know that clicking on text next to a radio button doesn't normally work; you have to click the actual button.)

Anyway, I wanted to improve the Dejal Store in a similar way, since it has sets of radio buttons to select the license levels for each product. It now looks the same as before, but when you point to a license for a product, the line is highlighted in grey, and you can now click anywhere in that highlighted space to select that license. When you do, the line is nicely highlighted with a blue background. The blue highlight works for the pop-up menus and receipt checkbox, too.

A challenge was that the page allows yellow product highlighting via a page argument - e.g. as used when clicking on a Buy Now link on the product pages. That is still supported:

This was all done via CSS for the styles, JavaScript for the click handlers, and PHP to generate the page with no code duplication. Each license line on the page is constructed via a PHP function call - every page on my site has at least a little PHP magic driving it. A JavaScript onclick handler on the license text simulates a click on the corresponding radio button, and JavaScript functions alter the class of the line based on whether it is selected, highlighted, or neither. The various highlights are done in CSS via classes, and the grey highlight is done purely in CSS via the :hover meta attribute.

The JavaScript code probably isn't all that elegant, since I'm not as familiar with that language as PHP etc, but it works. I am quite impressed with the JavaScript DOM (Document Object Model); it seems quite flexible. I've only had occasion to mess with JavaScript a few times (most recently redoing the screenshot pages, and for a Dashboard widget a while back), but I expect to do a lot more JavaScript stuff in the future, both on my site and in app contexts.

All this was created in Panic's excellent Coda application; my preferred web environment now.

Post WWDC wrapup

I'm back from WWDC now, and am in the process of moving into a shiny new 17" MacBook Pro with the high-res screen. A rather nice machine. I ordered it the day it was released, the Tuesday before WWDC, but unfortunately it didn't arrive till I was already at WWDC. Oh well... I'll have it for next time! :)

Anyway, it was a good week. I met many developers, including well-known people like Steven & Cabel of Panic (who I had met before, and who most deservedly won an Apple Design Award for Coda for Best Mac OS X User Experience); plus Daniel Jalkut of Red Sweater Software, Ken Case of The Omni Group, plus many other developers.

I've already talked about the Stevenote, and of course can't talk about the conference sessions, other than to say that I'm excited about Leopard, and am looking forward to leveraging its features in future versions of my apps.

WWDC has a number of interesting official and unofficial evening events. I enjoyed the sfMacIndie event on Sunday night, the official reception Monday night, the Apple Design Awards and Stump the Experts Tuesday night, the CocoaHeads gathering at the Apple store Wednesday night, and the WWDC Bash Thursday night.

Check out the photos of my trip to San Francisco and (non-NDA'ed) parts of WWDC.

At WWDC

So, I'm at WWDC currently. I've enjoyed meeting fellow developers (and several Dejal product users) around the conference center, at the sfMacIndie event, and the WWDC reception tonight.

I managed to get an okay seat for the Stevenote, a little back from the center of the room... but in a good position to see the repeater screens. I thought it was an interesting keynote, but with few surprises. I know some people are disappointed, but perhaps they had too high expectations?

So, how'd I do with my predictions? Let's see:

  • No hardware announcements: I was right with this one.
  • Possibly updated displays: nope... but not too surprising.
  • We might see a demo of iLife 07 and/or iWork 07: nope.
  • Steve will no doubt mention the iPhone, but there won't be a SDK: yep, called that one. I know this is disappointing for many people, but as I said, that may come later.
  • Steve will spend most of his time talking about Leopard: sure did.
  • The Finder might be rewritten: yes, though it seems more of a cosmetic overhaul than a full rewrite.
  • I've love to see more multi-touch features in the OS, but I don't think we're ready for that yet: yeah, no mention of that... oh well, it was a faint hope!
  • Maybe improved syncing features, to fit in with the iPhone: I seem to recall some mention of this?
  • The ZFS thing has been a popular rumor of late, but I have no idea whether that will eventuate: no mention of this, so perhaps it didn't... or perhaps Steve was annoyed by the "leak".
  • Probably some cosmetic changes in Leopard - using the newly fashionable dark metal styling for all windows, and other UI improvements: yes indeedy. I do like the dark metal, so a unified OS-provided look is a very good thing.
  • Probably no major new programmer APIs: so it would seem.

I seem to have done alright. Of course, my predictions were based on an aggregation of rumors, so hardly a reflection of my own prognostication abilities.

Anyway, on with the WWDC week... though of course I can't write about anything else discussed in the sessions.

Almost time for WWDC07!

Just another few days before WWDC07 kicks off!

I will be attending WWDC again this year, and am looking forward to the Stevenote, the various gatherings of Mac developers, and the conference sessions themselves.

There have been lots of rumors of what Steve Jobs will announce on Monday. For what it's worth, here are my guesses - not based on any inside information (I haven't run a Leopard seed since last year's WWDC), but based on rumors I've read, etc:

  • No hardware announcements: I don't see an updated iMac at WWDC, being a consumer machine. It is overdue, but will probably be updated at a later date.
  • Though updated displays could be possible, with iSight integration, since the standalone iSight is no longer available. I kinda hope not, since I just bought a 23" display!
  • We might see a demo of iLife 07 and/or iWork 07 (or will they call it 08, or something else?), but they won't be available till Leopard is out.
  • Steve will no doubt mention the iPhone, but there won't be a SDK. I wouldn't want them to release one yet; better to lock down the features and let people become familiar with the phone before allowing third-party development for it.
  • Steve will spend most of his time talking about Leopard.
  • The Finder might be rewritten. I personally use Path Finder, a great third-party replacement Finder, but Apple's Finder is definitely in need of improvement.
  • I've love to see more multi-touch features in the OS, but I don't think we're ready for that yet. I'd really like to see something like Microsoft Surface, done the Apple way.
  • Maybe improved syncing features, to fit in with the iPhone.
  • The ZFS thing has been a popular rumor of late, but I have no idea whether that will eventuate. Even if it is the default disk format, that won't necessarily affect existing disks, though, so it doesn't seem like too big a deal to me.
  • Probably some cosmetic changes in Leopard - using the newly fashionable dark metal styling for all windows, and other UI improvements.
  • Probably no major new programmer APIs; Apple would have had to tell us about them before now, to give developers time to get up to speed. But you never know.

Anyway, I could be totally wrong... but those are my guesses. We'll see in just a few days!

I will be wearing one of the several Dejal shirt designs, like the pictured one, so if you're there and see me, come up and say hi! Here's what I look like, too.

I will be at the sfMacIndie event on Sunday night, and hope to meet many fellow indie developers there. I might go to Buzz's party Monday night, or just hang out at the official WWDC reception. And I'll be around for the rest of the week, too.

Should be a great week!

Pan-Mass Challenge software auction

Seth Dillingham is hosting a Pan-Mass Challenge software auction, as a fundraising project in support of his 300-mile ride across the state of Massachusetts for a cancer care charity.

He wants to collect hundreds of software products, which will be auctioned on eBay starting in July.

This is a very worthy cause, so I am donating 5 Standard licenses for Dejal Simon, plus 5 Household licenses for Dejal Caboodle (about $400 total value). I encourage other Mac developers to join in, too.

For more information on the fundraising, click this image:

Kitten Caboodle

If you look closely at the Caboodle icon, you may notice a kitten in one of the documents overflowing from the bag.

For those interested, this isn't stock art, but is actually one of my cats as a kitten. His name is Pixel, named after the cat who walks through walls in Robert A. Heinlein's novels. Like the cat in the book, he's an orange tabby, and sometimes he seems to walk through walls, too. :)

Here's another picture of him as a kitten, and now:

PixelCloser

 

 

 

 

 

 

VT Memorial Fund results

I'm pleased to be able to report that the independent Mac developers that participated in the recent Virginia Tech Memorial Fund Charity Sale raised a total of $2,433.00.

Thanks to everyone who helped achieve this by buying Dejal and other participants' products on May 2.

Syndicate content