Not So Fast! Adobe Flex Still Alive?

I haven’t touched Flex projects in a couple of years now. Once the iPad came out all my Flex clients dropped Adobe Flash. We moved lots of code to HTML5 in the past several years.

For all that HTML5 has to offer, however, I have often missed some of the beauty found in the Flex environment. So recently when a new client asked me to take on some legacy Flex code for updates I began digging back into Flex.

To my surprise I find myself as happy as ever to code in ActionScript and Flex. I am also quite pleased to find how well the latest AIR platform supports iOS. It may just happen that my next iOS app will be written in Flex instead of in Objective-C or in HTML5 with PhoneGap.

Sounds fun!

Vagrant Disk Trashed When Upgrading VirtualBox Too Far

User beware… If you upgrade your VirtualBox too far ahead of the guest additions installed in Vagrant then you can end up with an instability that will trash your disks in the vagrant box and cause the file system to go read only.

I kept having readonly filesystem problems and they were getting more and more frequent. After combing the vagrant and virtualbox forums I saw some hints that it might be related to Guest Additions being too far out of date with the main VirtualBox version. After following the instructions here to get my guest additions up to date I’ve had no further trouble with a readonly file system.

Automator Workflow to Reduce Large PDF Files

When I worked in the Linux world I used a variety of command line tools to help reduce the size of large PDF files. In the Mac OSX world I started looking at converting some of my same scripts over to run on OS X. There were several tools I needed to install via MacPorts and as I started that process I realized there was probably a simpler way already built into OS X. Sure enough, there is: Automator.

To all you long time Apple users Automator is old news, but it was new to me. Here is how I created an Automator workflow (and then app) to reduce PDF large files down to size by shrinking the images inside the PDF.

Open Automator and choose to create a new application.
From the Library choose PDFs.
Drag the item labeled “Apply Quartz Filter to PDF Documents” to the workflow area.

I could choose the filter called “Reduce File Size” but I want to make some adjustments to it and the default filter is locked so click the Advanced options and from the list option-click (or two finger tap) the Reduce File Size filter and choose Duplicate.

Now spin down your copy of the filter and adjust the Image Sampling and Image Compression settings. For sampling I used 50% scale, 1024 max pixels, 128 min pixels and High quality. For compression I used JPEG mode and set the quality a few notches below Max.

Now in the filter dropdown at the top choose your Reduce File Size Copy filter.

I want the PDF to be opened after reduction so go to your library and choose Files and Folders and drag over the Open Finder Items action.

Make sure Open with is set to “Default Application”.

Now save your workflow and put your compiled app on your desktop or somewhere handy. Any time you need to reduce a PDF drop it on the app icon and your PDF will be reduced and opened in Preview.

PhoneGap + ChildBrowser – Opening all non-app links in ChildBrowser

I’ve been working on a PhoneGap project with iPad as the target. Most of the app runs from an external site so after presenting local files to handle the login form and authentication the main webview then shifts to an external site where the rest of the code runs.

We are using ChildBrowser to handle showing images and PDF files from the external site so that we can don’t have to include a navigation bar in our app. The ChildBrowser plugin helps us view those files without getting locked out of the original app. That’s just the background. Now we have a new problem. Many pages in this app link to external sites that are not part of the main application. We needed ChildBrowser to handle all non-app site requests automatically so that external sites would open in the popup and not replace the view in the main UIWebView of PhoneGap. Here is how we solved it:

We started with the PhoneGap.plist preferences file. In the ExternalHosts array within that plist we added all the possible host combinations that our app considers as local to the app. This app has about seven url host variants that could be used within the app so all of those should open in the main WebView. Any host not listed in ExternalHosts should open in the ChildBrowser. Keep in mind that to allow all external sites to open we still had to put * as an entry in ExternalHosts but this doesn’t affect the logic below.

In AppDelegate.m didFinishLaunchingWithOptions method I added this logic to load the PhoneGap.plist into a Dictionary and read the ExternalHosts into an array. If anyone can tell me this is already loaded somewhere and I could have skipped this step let me know in the comments:

NSDictionary *phoneGapPrefs = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"PhoneGap" ofType:@"plist"]];
self.internalUrls = [[NSArray alloc] initWithArray:[phoneGapPrefs objectForKey:@"ExternalHosts"]];

I’m assuming you know how to create the internalUrls variable as an instance variable in AppDelegate.h. Now I have an array of all my internal host names so that any requests that don’t match that are loaded in ChildBrowser. Now we proceed down to the shouldStartLoadWithRequest method where I add this logic to check if we’re loading an external site (starts with http) and check if that site is part of our internalUrls array.


if ([[url scheme] isEqualToString:@"http"] || [[url scheme] isEqualToString:@"https"]) {
    //This code will open any url that is not in the PhoneGap whitelist in Child Browser
    if (![m3Urls containsObject:[url host]])
    {
        [theWebView sizeToFit];
        ChildBrowserViewController* childBrowser = [ [ ChildBrowserViewController alloc ] initWithScale:FALSE ];
        childBrowser.modalPresentationStyle = UIModalPresentationFormSheet;
        childBrowser.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;   
        [super.viewController presentModalViewController:childBrowser animated:YES ];   
        NSString* urlString=[NSString stringWithFormat:@"%@",[url absoluteString]]; 
        [childBrowser loadURL:urlString];
        [childBrowser release];
        return NO;      
    }
    return YES;
}

Now all urls that start with http or https as the scheme and are not in the ExternalHosts I’ve listed are considered external to our app and are loaded in ChildBrowser. At this point you might tell me that since I’m listing * as a valid ExternalHost I don’t need to list all the site-specific urls and you’d be correct as far as avoiding the whitelist. During initial development I didn’t even anticipate opening non-site urls so all I wanted to list were the site-specific urls for this app. Later on I added the * for allowing any url, but realize that listing all my internal app urls provided an easy way to accomplish my need to determine which urls were for my app and which were references to non-app sites.

Find parent form in jQuery

Needed to find the parent form of a form element. This answer on StackOverflow gave me the right answer.

Problem with jQuery-UI Draggable and Form fields – Solved!

I’ve been using the Draggable functionality of jQuery-UI on a project and ran into a new problem. I needed to add form fields like SELECT and INPUT in my draggable div. Unfortunately, since my container itself is draggable it prevents clicking anything inside the container from being selected so I can’t choose items from the dropdown or focus on the input box to type text.

The solution is rather simple. Just add the appropriate selectors in the cancel option of Draggable. Actually, in my case I’ve migrated to Sortable so I added it there. Now my cancel option looks like: “select, input”. Works like a champ!

Help! Where’s My App Switcher Gesture in Lion?!

I rarely upgrade any OS when it is first released. This was always my practice with Windows, then Linux and now with OS X. So when Lion was released back in the Summer I passed on the chance to be first in line. Then 10.7.1 came out and I still waited. But with the arrival of iOS 5 and iCloud it was time to upgrade in order to take advantage of PhotoStream among other things.

I’m a huge fan of trackpad gestures and so I was pretty happy that Lion expanded the use of gestures, but I was shocked that my most often used gesture from Snow Leopard, the four finger swipe to open the Cmd-Tab application switcher, was gone. Cmd-Tab still opens the old application switcher but the familiar four finger swipe is gone and now there is a three finger swipe that invokes a switch between the new Lion desktops and full screen apps. So unless I run all my apps full screen, the switcher just goes between Dashboard and the main Desktop. Not what I want at all!

After half a week of frustration and searching for a solution I found BetterTouchTool. BTT gives me back everything I lost and more! I left the three-finger swipe alone and now have a four-finger swipe that opens up my long lost Application Switcher. BTT doesn’t stop there, however. It has an advanced application switcher where I can start the swipe and leave one finger on the pad and while still touching the pad, move the cursor to my desired application and then let go of the pad. With a few seconds of training my brain, I now switch applications faster than I ever did under Snow Leopard.

If you’re longing for more out of your trackpad or magic mouse, you must give BetterTouchTool a try. At the very least it restores lost functionality to Lion, but I think you’ll find it adds even more possibilities to gesturing than you had previously imagined.

DropBox vs SugarSync – Or why I’m keeping DropBox

I’ve used DropBox for quite some time now and loved it. When I needed more default storage, however, a friend pointed me in the direction of SugarSync. SugarSync offers a range of different features, but my clear favorite is the ability to flag any folder on my machine as a sync folder. No longer do I have to put my sync files in the DropBox folder, I can sync any of my standard folders and leave them in place.

SugarSync also maintains a distinction between which files came from which of my computers or mobile devices so if I want files specifically from my laptop instead of my desktop the mobile clients show that distinction.

Combine that with a base storage allocation of 5GB and SugarSync looks like the clear winner. Almost.

After two months of using SugarSync I still find myself using DropBox far more often in my day to day routine and there is one simple reason: mobile integration. It seems every app that I care about on my iPad and iPhone allows for DropBox interaction. If I want to work in Office2HD for example or PrintCentral or a myriad of other apps, all of my files have to be in DropBox. For reasons I haven’t explored, SugarSync does not have built-in support in any of the apps I use.

So while it is wonderful to have more storage and sync any folder on my machine, when I want to edit files in my mobile devices DropBox is the go to storage medium. Thus here I am two months later still using DropBox as my mobile storage medium and SugarSync as my cloud backup medium.

Maybe iCloud will change all that but somehow I still think DropBox is going to be my the storage medium of choice for some time to come. We’ll see.

Flash waning, HTML waxing?

Just an example from my own development contracts that Flash apps appear to be on the wane. I spent 3 1/2 years developing a Flash application using Adobe’s Flex technology. The app went live less than a year after we started and we spent the next 2 1/2 years adding features and improving the application. Then in the Fall of 2010 the customer asked how quickly we could rewrite the entire thing in html and javascript!

It took us (me and their own inhouse development staff) three months to rewrite the entire app in html+javascript to a beta version level. One of the key motivations was having a desktop version that worked on the iPad and having a mobile version that shared the same basic codebase as the desktop.

Now that we’re basically finished with the app and polishing the mobile version to work on iOS, Android, etc. it is hard to remember ever using the app in Flex. As much as I hate to admit it, HTML + AJAX has been far faster and less cumbersome to develop for than Flex. We had a very good Flex codebase using very good design patterns. The code was centered around the Cairngorm framework and everything was well modeled in the MVC2 pattern, but in the end, lack of developers with thorough Flex knowledge and desire to have it run on the iPad (and other tablets) drove us to html and javascript.

No looking back now.

Recursive Stored Functions in MySQL

I have only recently started working heavily with stored procedures and functions in MySQL. After years in the Oracle world with advanced stored procedures, functions and packages, I’ve had to come to grips with the shortcomings of MySQL. One of those is recursive functions. MySQL allows recursive stored procedures, but not recursive stored functions. Here is my workaround…

First create your main logic as a stored procedure with an OUT variable:

DELIMITER |
CREATE PROCEDURE my_recursive_proc(a_some_parameter INTEGER, OUT a_result INTEGER)
BEGIN
    DECLARE v_my_number INTEGER DEFAULT 0;
    -- Have to set max_sp_recursion_depth inside the stored procedure
    SET max_sp_recursion_depth := 20;
    SET v_my_number := v_my_number + a_some_parameter;
    IF v_my_number < 100 THEN
        CALL my_recursive_proc(10, v_my_number);
    END IF;
    SET a_result := v_my_number;
END |
DELIMITER ;

So now I have a recursive procedure that calls itself adding 10 to the initial number until we get to 100. In the real world we'd be doing something serious like descending through related child records until we find some search result. What I really want now is a function I can call in a WHERE clause somewhere.

Here's all we have to do:

CREATE FUNCTION my_recursive_func(a_some_parameter INTEGER)
    RETURNS INTEGER
BEGIN
    DECLARE v_result INTEGER DEFAULT 0;
    CALL my_recursive_proc(a_some_parameter, v_result);
    RETURN v_result;
END |
DELIMITER ;

Now in my SELECT statements I can do:
SELECT * FROM my_table WHERE my_recursive_func(some_column) = 100;