2012-10-31

Custom URL scheme in iOS

iOS, Android, and some other operating systems allow an app to volunteer to handle certain kinds of hyperlinks. Besides the usual http:// and mailto:// and ftp:// sorts of links, you can create your own links. I could, for example, create my own basil:// link. Indeed, this is the main avenue Apple provides for applications to talk to each other in iOS.

For more information…

Launching Your iPhone App via Custom URL Scheme by Rodney Aiglstorfer. He gives detailed steps with screen shots showing how to implement your own scheme.

Apple provides a brief intro to this topic, along with other Advanced App Tricks.

Apple documentation on the URL schemes built into iOS for calling the mail, phone, texting, Google Maps, Google YouTube, and iTunes apps.

2012-09-28

Generate a UUID in Objective-C (iOS)

I am surprised to find that even by 2012 Apple has yet to include an object type for UUID. Nor do they provide an easy way to generate a UUID. Java does both.

The blog post Creating a GUID or UUID in Objective-C by Don McCaughey provides source code for a nice method to wrap Apple's clumsy UUID feature in Core Foundation. Unfortunately his 2010 code is not working for me Xcode 4.4.1, apparently because of ARC.

Error:
Cast of C pointer type 'CFStringRef' (aka 'const struct _CFString *') to Objective-C pointer type 'NSString *' requires a bridged cast

Two fix-its offered. I chose this one:
Use CFBridgingRelease call to transfer ownership of a +1 'CFStringRef' (aka 'const struct _CFString *' into ARC

And I deleted his call to autorelease.

Here is my revision to Mr. McCaughey’s code. My revision seems to be working. But is memory managed correctly? I am still too new to Objective-C and C to grasp the nuance of bridging OOP and POC (Plain Old C). Please post corrections or criticism.


//=================
    // Return a new UUID string. Built for ARC in iOS 4 and later.
- (NSString *)generateUuidString
{
        // create a new UUID which you own
    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
    
        // create a new CFStringRef.
    NSString *uuidString = (NSString *)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid));
    
        // release the UUID
    CFRelease(uuid);
    
    return uuidString;
}
//=================

StackOverflow.com has a thread on this topic.

2012-08-09

The Modern Way to Store Passwords - BCrypt

When authenticating users, you should never store their password value directly. The proper way is to salt and hash before storing.

Most hashing algorithms are designed to take a large amount of data such as documents and quickly return a hash. For storing passwords, you want the opposite: small data, and slow (strong) hashing.

Recognizing this different need, BCrypt takes a different approach. BCrypt uses the very strong but slow Blowfish cipher to do the hashing. BCrypt generates a random salt value to be added to the password, changing on each usage. Furthermore, and most importantly, BCrypt is adaptive. That is, as computing technology speed increases, you can increase the the strength of BCrypt by passing an increasing number. Though oversimplifying, you can think of the number as indicating the number of iterations of hashing and re-hashing. As computers get faster in the future, you can increase the strength of your hashing by passing a higher numbers.

For more info, read the original paper by  Niels Provos and David Mazieres. Read a brief overview by Coda Hale. Read this entertaining article by Thomas Ptacek.

Postgres 9 has a crypto module that includes a "crypt" command that seems to implement BCrypt. Here's a example of calling that command, where 'bf' means Blowfish:
    SELECT crypt('YourPasswordGoesHere', gen_salt('bf', 10));

Returns a hash value like this:
     $2a$10$Tq0dC2EDyqKhFbjQpu42b.Hzvg4dntLSZPFfvacmzKqR0E6uIRUyG

Increasing that number slightly dramatically increases the burden on a comupter. Here's some results of calling that in Postgres 9.0.4 on Mac OS X 10.6.7 on a MacBook with a 2.4 GHz Core 2 Duo.
  • 6 ≈ 40 milliseconds
  • 8 ≈ 130 ms
  • 10 ≈ 500 ms
  • 12 ≈ 1,600 ms
  • 14 ≈ 7,000 ms
  • 16 ≈ 28,000 ms (half a minute)
  • 21 ≈ 1 million ms (17 minutes)
During this time, the calculation took about 80-100% utilization of a CPU core.

BCrypt has been implemented in many languages, including C, Java, Python, Ruby, and more.

An implementation is bundled with Postgres, at least when using the installer for Mac OS X provided by EnterpriseDB. At least it seems to me that you are getting BCrypt if you specify the 'bf' argument, but the docs are not explicit -- Please correct me if I'm wrong.

To use this in Postgres,  you must enable the "pgcrypto" functions, by copying and executing the SQL found in the "pgcrypto.sql" file found someplace such as this:
    /Library/PostgreSQL/9.0/share/postgresql/contrib/pgcrypto.sql
Open that file, copy and paste to an interactive SQL window in the pgAdmin app. Actually, you only need the first third of that file's SQL, down to but not including the "pgp_" functions.

    2012-06-05

    New GUI in Mountain Lion

    I took a look at these screen shots of pre-release Mountain Lion Server, now 3 months old.

    Here are some differences I noticed in the GUI widgets. No big drastic changes, but interesting to those of us building data-entry/database oriented software. Perhaps some of these are in Lion, but not that I’ve noticed.
    • On the read-only panels (without data-entry) they have:
      • Greyed-out field labels
      • No colons on the labels (Apple has never been consistent on label colons)
    • Grey trim around the data-entry panel, making it look like an index card floating above a surface
    • Extra large & bolded fonts for grouping label
    • Centered tabs
    • "Edit…” buttons, presumably to present further data-entry dialogs or assistance
    • Slightly different presentation of +/-/✎ buttons
    • “Cancel” & “Done” buttons
      • Not “OK” 
      • Set inside a grey panel
    • White background in main data-entry area, but grey background in header and footer areas. 
      • Yet sheets are the opposite, white b/g for title but grey for data-entry.
    • The grey footer seems inconsistently used. 
      • Or perhaps the grey footer is present only for panels that have undoable actions and after the user does some data-entry then the Cancel/Done buttons appear in that grey footer.

    2012-06-04

    My Portable Office

    Man Without An Office, Out and About

    I often work at any place that strikes my fancy. Sometimes at home, sometimes at the home of a colleague or a friend, and occasionally for an hour or two at a coffeehouse. After some trial and error, here's a list of the gear I've found useful for nomadic work.

    Monitor – Viewsonic VX2450wm-LED

    LED-backlit is a must. Smooth coverage across the screen and bright. One inch thin. Should last for decades or longer. Lightweight and easy to carry. And LED requires very little electricity, which is important to avoid overloading household wiring.

    This Viewsonic model is the best monitor I've found not only because of high-quality and low-price ($200), but because of this surprising consideration: portability and easy to stow. For the nomadic use, the monitor should be easy to put out of the way and easy to move from place to place. This ViewSonic has a removable base that simply unscrews from underneath. Even better, the screw is designed to stay attached and not fall out, so you don't lose it. Secondly, this monitor has the right kind of box. The box is compact, with a sturdy lid and built-in handle, and robust tab slots for locking shut. Inside are pieces of styrofoam that slide easily onto the left and right sides of the monitor. The styrofoam is the compacted solid type, rather than the open-cell kind that rapidly falls apart into disintegration.

    By comparison, Dell uses an all-cardboard box which, while green, does not make for easy or durable re-use.

    The ViewSonic also tilts, which seems like no big deal until you use a monitor that doesn't.

    The ViewSonic has such a low price that I've bought more than one, stashing them at homes where I tend to visit.

    Viewsonic sells a 22-23" model alongside this 24" model. There is not much difference in price any longer, so I recommend the larger pixels for aging eyes like mine. The other model has a noticeably more compact and lighter box, so you may consider that one as well.

    I strongly recommend getting a monitor with full-DVI resolution, 1920 across by 1080 high pixels. There are still many monitors with fewer pixels, but without the cost savings of yesteryear, so avoid them.
    Big tip: Rather than use the usual clunky DVI cable with a clunky mini-DisplayPort adapter, buy one of these sleek mini-DisplayPort to DVI cables from Monoprice.com that eliminate the need for an adapter. Heck you can buy 2 or 3 for the cost of a single Apple-brand adapter. But double-check your order with Monoprice.com, as they sell both full-size DisplayPort as well as smaller size mini-DisplayPort. Your MacBook takes the mini-DisplayPort.

    Some newer monitors come with only an HDMI port rather than a DVI port, because they come from the factories aimed at the television markets. I've not tried any, but I suppose they should work well with your Mac given the correct cable or adapter, such as these HDMI to mini-DisplayPort cables from Monoprice.com.

    Computer – Apple MacBook

    Of course the MacBook is standard gear for office nomads. I chose a smaller size screen since I use the external monitors most of the time.

    I suggest buying an extra power supply. I have one I keep with me in my backpack. That leaves one at the ready in my home office. Apple sells two power supply models, one 65-watt and one 85-watt meant for the larger and more power-hungry MacBook models. I usually buy the 85-watt model for maximum compatibility with any Mac model, as they work fine with MacBooks that only need 65-watt. The 85-watt models are a bit larger and heavier, but not by much in the recent incarnations.

    Reminder: Apple is replacing, at no cost, old MagSafe power adapters with frayed wiring or similar problems, as part of a lawsuit settlement. Just take your old faulty adapter to an Apple Genius appointment to see if it qualifies.

    Mouse – Apple Magic Mouse

    My favorite mouse of all time is now called the Apple Mouse, with the rubber roller ball on top. Once sold in a Bluetooth model, it now is only available with a tail.


    That roller ball is also a button, and I always set that button to switch apps, the same as pressing Command+Tab. I found that extremely useful and intuitive to use as I tend to spend my working hours switching back-and-forth between programming tools, documentation in PDF readers (Apple Preview or Adobe Reader), documentation in web pages, and email. This feature in unfortunately missing in Apple's newer touch-surface mouse.
    Grudgingly, the new Apple Magic Mouse with the amazing touch-surface is becoming my new favorite. At first I did not like this mouse at all. But with the advent of Lion, Mac OS X 10.7, this mouse now makes more sense as Lion brings a new set of gestures you can make on the touch surface.

    Bluetooth users beware: Some Bluetooth mice have no power On/Off switch, or have a difficult switch. For stowage in a backpack, you really want a good switch to prevent the battery from being drained.

    Tip: For stowing in my backpack, I use the original plastic jewel box in which the mouse arrived. I kept the plastic tray inside, to hold the mouse. The box is surprisingly strong. Using the box keeps the mouse protected, and prevents the battery-draining power switch from sliding to the On position.

    Another tip: Get a flat-surface teflon-style mouse pad. When out and about, you may encounter surfaces unfriendly to your mouse. Also, stash one or two of those alcohol swipes that come in a foil packet to clean away mouse gudgies.

    Keyboard - Microsoft Bluetooth Mobile Keyboard 5000
    I am not usually a Microsoft customer. But I have found this ergonomic-style keyboard to be significantly more comfortable than Apple's straight keyboards. They keys' shape and location prevent the bent-wrist position that aggravates carpal-tunnel problems.

    Unfortunately, Bluetooth and ergonomic seem to be mutually exclusive terms. I’ve found no other options but this one. Fortunately this Microsoft keyboard works well enough with Mac computers. It has Windows-logo and Alt keys rather than Command and Option keys, but you can either get used to them, or change their meaning on your Mac in the System Preferences > Mouse panel. You can even slap on a piece of colored electrical tape to cover up that Windows logo.

    Actually, I bought the "6000" version of this keyboard. My model cost more than twice the 5000 price and came with a separate Bluetooth keypad which I never used and gave away. From what I've read, the 5000 is basically the same as the 6000 and I presume it will work well fellow Mac users.

    Backpack - Brenthaven Expandable Trek Backpack for MacBook

    Seattle is riddled with car prowlers as the Seattle Police Department chooses to blame the victim rather than bust criminals like other cities do. So I need to keep my gear with me rather than ever leaving it in my vehicle.
    I use a previous edition of this excellent backpack from Brenthaven. Built like a tank, looks brand-new after years of use, and made to fit your MacBook gear.

    2012-05-24

    Minimal HTML5 Document

    Here is the best page I've yet to find summarizing the minimum you need when starting a new HTML5 page. Concise and correct. 'Correct' is important -- there is much misinformation floating around about basic requirements of HTML5 and about good practice of fall-back compatibility with lame browsers.

    2012-04-27


    Oracle announced the official release of the JDK for Java SE 7 Update 4 on Mac OS X (Lion), as of 2012-04-26. No more need for the tricks discussed on this page.
    Installation is simple per these instructions:
    1. Download from the usual place on the Oracle web site.
    2. Mount the DMG.
    3. Run the installer.
    This release has a few limitations, most notably the lack of support for Web Start and the Java Plugin for web browsers. That support is expected later this year.
    After installing, read the JDK for Mac ReadMe. Most importantly, if you want Java 7 to be the default, drag it to the top of the list in the Java Preferences app found in your Utilities folder.
    Mac OS X easily supports multiple JVMs simultaneously. Each is now found here:
    /Library/Java/JavaVirtualMachines
    
    This geek gets a thrill seeing Mac OS X listed as a "Certified System Configuration".
    By the way, Apple provides a mailing list for developers’ technical issues related to Java on OS X.

    2012-04-07

    No need to adjust memory configuration when installing Postgres on Mac

    EnterpriseDB.com is kind enough to provide the Mac OS X installer for Postgres.  Using that installer is even easier that it seems.

    The last few versions such as 9.1 come bundled with a ReadMe that is misleading. The ReadMe states that you need to adjust your shared memory configuration. Actually, the installer does this for you.

    [1] Download and run the installer.

    [2] Read the following message displayed by the installer.

    [3] Restart your Mac.

    The installer installs some script to automatically launch the Postgres engine when your Mac starts.

    [4] Run the installer again to complete the installation process.

    I am recording here the last last sentence in that message, for future reference:
    If you wish to restore the default [memory configuration] settings in the future, simply delete the /etc/sysctl.conf and reboot.

    2012-03-06

    How fast does Vaadin 6 render a layout?

    [Update: I altered this app to separate the time taken as overhead when launching the Vaadin app from the time taken to create a complex form. The app now launches with a simple form displaying a button that takes the user to a complicated form.]

    "Peter" on StackOverflow.com claimed that a complicated form takes 10 seconds with Vaadin, but less than a second on some other web app framework. I took that as a challenge. Using his specification:
    form with 3 column - each column contains 6*label+input, 2 tables, 12 buttons
    I created a Vaadin 6.7.5 app that looks like this (when shrunken down):

    Hopefully you may find the app up and running.

    My Results

    My results when launching this app and rendering this layout…

    • Less than a single second when run locally on my MacBook, Intel Core 2 Duo at 2.4 GHz.
    • 8-12 seconds the very first time served from Apache Tomcat 7 on a Mac mini 2.53 GHz running Mac OS X Snow Leopard across the Internets via DSL connections or a Starbucks’ wifi.
    • After the app launches, a complex form can be built and displayed in a second or two. 
    So, in the usual case of deployment using modest resources, a Vaadin app’s initial launch has an overhead of about 8-12 seconds. But after initialization, layouts appear in a second or so.

    Furthermore, I added some tests for elapsed time within the app. That testing shows that server-side creation of the complex form takes only about 7 milliseconds.  Each GridLayout instance takes about 1-2 milliseconds. So most of that second or two it takes for the form to appear must be time spent transmitting the description of the form to the browser and then the browser rendering on screen.

    About My Implementation

    I tried not to "cheat" by over-optimizing. I generate three instances of the same GridLayout, each representing the "3 columns" mentioned by Peter. The buttons each have a separate listener object that react to a click. Each of the tables is created with its own set of data -- no sharing. Seems like a realistic setup to me.

    Here is the source code. Contained in a single class for your copy-paste convenience. I’m sorry Blogger.com has no support for presenting source code.


    package com.example.triplegrid;


    import com.vaadin.Application;
    import com.vaadin.ui.*;
    import com.vaadin.ui.Button.ClickEvent;


    /**
     * This example Vaadin 6.7.5 app was created to meet a challenge by "Peter" on StackOverflow.com
     * http://stackoverflow.com/questions/3888233/cons-related-to-vaadin
     * 
     * Peter claims that a complicated layout such as this takes 10 seconds to load.
     * 
     * I found that launching this app and rendering this layout takes less than a second
     * when run locally on my MacBook, Intel Core 2 Duo at 2.4 GHz.
     * 
     * I found that launching this app with the simple layout over the Internet to a Starbucks' wifi
     * takes 12 seconds the very first time. Apparently the initial loading of the Vaadin framework’s
     * libraries to the web browser takes about 10-12 seconds to download and initialize. Clicking the
     * "Create triple grid layout" button takes less than 2 seconds to create and show the layout.
     * So, yes, a Vaadin app has 10 second startup overhead. But after that complex forms need only a 
     * second or two to appear.
     * Served from Apache Tomcat 7 on a Mac mini 2.53 GHz running Mac OS X Snow Leopard.
     * 
     * Peter gave this brief description as the specification for his form:
     * form with 3 column - each column contains 6*label+input, 2 tables, 12 buttons
     * I created 3 GridLayout layouts in Vaadin to implement Peter's 3 columns.
     * 
     * © 2012 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
     * 
     * @author Basil Bourque
     * 
     */
    public class TriplegridApplication extends Application {


        HorizontalLayout outerLayout = null;


        @Override
        public void init() {
            // Challenge by "Peter" of StackOverflow:
            // form with 3 column - each column contains 6*label+input, 2 tables, 12 buttons


            // To meet that challenge, I am using 3 instances of a GridLayout, one for each of Peter's 3 columns.


            long appStart = System.currentTimeMillis();


            this.outerLayout = new HorizontalLayout();
            this.outerLayout.setMargin( true );
            this.outerLayout.setSpacing( true );


            Label appInitWhen = new Label( "App’s init() method ran: " + new java.util.Date().toString() );
            this.outerLayout.addComponent( appInitWhen );
            
            Button createTripleGridButton = new Button( "Create triple grid layout" );
            createTripleGridButton.addListener( new Button.ClickListener() {


                @Override
                public void buttonClick( ClickEvent event ) {
                    long tripleGrid_Start = System.currentTimeMillis();
                    createAndShowTripleGrid();
                    long tripleGrid_Elapsed = System.currentTimeMillis() - tripleGrid_Start;
                    getMainWindow().setCaption( "Triple Grid - New form: " + tripleGrid_Elapsed + " ms" );
                }


            } );
            this.outerLayout.addComponent( createTripleGridButton );


            Window window = new Window( "Triplegrid Application" );
            window.setContent( outerLayout );


            long appElapsed = System.currentTimeMillis() - appStart;
             window.setCaption( "Triple Grid - App initialization: " + appElapsed + " ms");
            setMainWindow( window );
        }


        public void createAndShowTripleGrid() {


            Button closeAppButton = new Button( "Restart app" );
            closeAppButton.addListener( new Button.ClickListener() {


                @Override
                public void buttonClick( ClickEvent event ) {
                    close(); // Close this app instance.


                }


            } );


            Layout grid1 = this.makeGridLayout();
            Layout grid2 = this.makeGridLayout();
            Layout grid3 = this.makeGridLayout();


            this.outerLayout.removeAllComponents();
            outerLayout.addComponent( closeAppButton );
            this.outerLayout.addComponent( grid1 );
            this.outerLayout.addComponent( grid2 );
            this.outerLayout.addComponent( grid3 );
        }


        private GridLayout makeGridLayout() {
            // Challenge: each column contains 6*label+input, 2 tables, 12 buttons)
            // We'll do 6 rows of label, field, button, button.
            // Then we'll add 2 tables at bottom.


            long gridStart = System.currentTimeMillis();


            GridLayout grid = new GridLayout();
            grid.setSpacing( true );
            grid.setMargin( true );
            grid.setColumns( 4 );
            grid.setRows( 6 + 2 ); // 6 rows of fields, plus 2 rows of a Table each.


            for ( int i = 1; i <= 6; i++ ) {
                Label label = new Label( "label " + i );
                label.setSizeUndefined(); // Fix a quirky "feature" of Vaadin that Labels by default can collapse (not display) in GridLayout).
                grid.addComponent( label );
                TextField field = new TextField();
                field.setWidth( ( "Stop ms: 1331142285223".length() - 9 ) + "em" ); // Use example text to gauge width.
                grid.addComponent( field );
                grid.addComponent( this.makeButton( "alpha" ) );
                grid.addComponent( this.makeButton( "beta" ) );
                // GridLayout's cursor auto-wraps to next row of GridLayout because we used the last (4th) column.
            }


            // Add 2 tables.
            Table table1 = this.makeTable( "First of two tables" );
            Table table2 = this.makeTable( "Second of two tables" );
            // Each table spans across all four columns of a single row.
            // GridLayout's cursor auto-wraps to next row of GridLayout because we used the last (4th) column.
            grid.addComponent( table1, 0, grid.getCursorY(), grid.getColumns() - 1, grid.getCursorY() );
            grid.addComponent( table2, 0, grid.getCursorY(), grid.getColumns() - 1, grid.getCursorY() );


            TextField startField = (TextField) grid.getComponent( 1, 0 );
            TextField stopField = (TextField) grid.getComponent( 1, 1 );
            TextField elapsedField = (TextField) grid.getComponent( 1, 2 );


            long gridStop = System.currentTimeMillis();
            long gridElapsedTimeMillis = ( gridStop - gridStart );
            startField.setValue( "Start ms: " + gridStart );
            stopField.setValue( "Stop ms: " + gridStop );
            elapsedField.setValue( "Elapsed ms: " + gridElapsedTimeMillis );


            return grid;
        } // End of method.


        private Button makeButton( String caption ) {
            Button button = new Button( caption );
            button.addListener( new Button.ClickListener() {


                @Override
                public void buttonClick( ClickEvent event ) {
                    getMainWindow().showNotification( "Ignore me", "<br/>This button does nothing." );
                }
            } );
            return button;
        } // End of method.


        private Table makeTable( String caption ) {
            Table table = new Table( caption );
            table.setSelectable( true );


            /*
             * Define the names and data types of columns.
             * The "default value" parameter is meaningless here.
             */
            table.addContainerProperty( "First Name", String.class, null );
            table.addContainerProperty( "Last Name", String.class, null );
            table.addContainerProperty( "Year", Integer.class, null );


            /* Add a few items in the table. */
            table.addItem( new Object[] { "Nicolaus", "Copernicus", new Integer( 1473 ) }, new Integer( 1 ) );
            table.addItem( new Object[] { "Tycho", "Brahe", new Integer( 1546 ) }, new Integer( 2 ) );
            table.addItem( new Object[] { "Giordano", "Bruno", new Integer( 1548 ) }, new Integer( 3 ) );
            table.addItem( new Object[] { "Galileo", "Galilei", new Integer( 1564 ) }, new Integer( 4 ) );
            table.addItem( new Object[] { "Johannes", "Kepler", new Integer( 1571 ) }, new Integer( 5 ) );
            table.addItem( new Object[] { "Isaac", "Newton", new Integer( 1643 ) }, new Integer( 6 ) );


            table.setPageLength( table.size() ); // Draw table just big enough to show all rows.
            return table;
        } // End of method.


    }  // End of class.

    2012-02-13

    Help with Argument Validation in Java

    The blog post Google Guava vs Apache Commons for Argument Validation is exactly that, a concise well-written comparison of the two. Conclusion: They are both good, but Guava may be a bit cleaner/simpler than Commons.

    This post is one amongst many in this good list of Guava-related resources.

    2012-02-09

    Ditto on My Opinion of Vaadin

    This article echoes my opinion about Vaadin toolkit for building business/desktop-style apps that happen to be delivered in a web browser.

    2012-01-29

    Disabling Annoying Window-Opening Animation in Lion

    I'm liking my new Lion install. Mac OS X 10.7.2 seems to run faster than ever, especially in terms of graphics. And I like Apple's choice to generally tone-down the colors and flashiness in the user interface. Apple heads in the opposite direction of Microsoft as Redmond continues to turn up the visual volume-knob on the in-your-face interface of Windows.

    Unfortunately, Apple made one poor choice. Lion now has a subtle but annoying animation on every single window as it opens. A zooming rectangle grows from a central point outwards before the actual window appears. It serves no useful purpose. May sound like no big deal, but after working a long while and staring at the screen, all those window-zooms made me dizzy.

    While System Preferences is ignorant of this feature, nevertheless you can disable this animation. Just copy-paste this single line in Terminal.app:

    defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool NO

    I found this useful tip in the amazingly thorough review of Lion by John Siracusa. I highly recommend that article when you upgrade to Lion.

    Another animation to kill: the shrinking/zooming effect when triggering Mission Control. To disable:
    defaults write com.apple.dock expose-animation-duration -int 0; killall Dock
    To re-enable:
    defaults delete com.apple.dock expose-animation-duration; killall Dock
    If only we could kill the nauseating sliding of entire screen when using the shortcut (two-finger swipe on Magic Mouse) to switch between Spaces or full-screen apps.

    Port Scanning

    If you need to see if your Mac has any software currently listening on a particular port, you can run this at the command-line (in Terminal.app or Path Finder):

    /Applications/Utilities/Network\ Utility.app/Contents/Resources/stroke 127.0.0.1 5432 5432

    That example is looking for the default port to the Postgres database server. Another example would be Apache Tomcat and other web servers that default to port 8080:

    /Applications/Utilities/Network\ Utility.app/Contents/Resources/stroke 127.0.0.1 8080 8080

    Why repeat the port number? Because you can scan a range of ports. The first number is the start of a range, the second number is the end of the range.

    And besides this command-line approach, you can use the Network Utility app bundled with your Mac in the Utilities folder:
    /Applications/Utilities/Network Utility.app

    2012-01-25

    Enabling JRebel

    To use the current version of JRebel in Eclipse Indigo, you must make these settings in each project:

    1. Turn on Build Automatically from Project menu.
    2. Generate rebel.xml file by context-clicking the project name. 
    For web work:
    1. When defining a server such as Tomcat or Jetty, set the Publishing property to Never publish automatically.
    The JRebel configuration wizard says: For Web projects, JRebel expects to find the rebel.xml configuration file in the WEB-INF/classes directory in the target .war file.

    2012-01-16

    New Web Site for 4D Plugins by Heubach Media

    Heuback Media has launched a handsome new web site dedicated to their excellent 4D plugins. Spun off from their main web site Heubach-Media.de, the new hmPlugins.com web site focuses on their commercial plugins hmCal, hmReports, hmTAPI (phone integration), hmBarCode, and the handy free-of-cost hmFree.

    Note that old links to the old home of these plugins are now broken.