How to hide icon in your dock for any Mac application

Just got a beta of a Mac notifier for Podio and didn’t like it showed both an icon in my menubar and my dock (sometimes also referred to as the taskbar). If you want to avoid having any Mac application shown in your dock, it’s possible to patch its package by doing these simple steps

  • Open Finder and browse to your application
  • Right-click the file and select “Show Package Content”

  • Browse to “Contents” and open “Info.plist”

Showing contents of a package

If you find an element called “Application is agent (UIElement)” you can mark its checkbox. If it does not exist you should add it by clicking “Add Item”, enter “LSUIElement” and mark the checkbox.

Now save your Info.plist file and restart the application.

Done. The dock icon is now hidden.

Just a warning .. this might not work for all applications e.g. if the application contains a menu that will only show the application is focused. So if you can’t access a window for that application through its menubar icon you are out of luck.

Use sensible defaults when building a web, mobile or desktop application

While working on migrating “gomore.dk”, a Danish ridesharing service, to Rails 3, I figured it would make sense to look into the existing database to figure out if I could add some sensible defaults when creating e.g. new rides. The site already contains a decent database so I figured it would be rather easy to measure which defaults to use.

As an initial example, I would like to know how many seats were shared on each trip and therefore I did a simple query as shown below:

Number of seats available for created rides on gomore.dk

From this, it is pretty obvious that I should use “3” as a default number of seats available. In this case, some common sense would probably give you the same result (four seats in a standard car minus one for the driver).

Same type of query can be used to figure out the most popular seat price:

Default price per seat for gomore.dk rides

It is even possible to remove options if you look into providing sensible defaults for your users. As in this case where the existing gomore.dk contains a checkbox for specifying if car is “smoking” or “non smoking” area. A query showed me

Smoking vs non smoking on gomore.dk

i.e. we really don’t need to have users decide on this .. more than 95% of all rides are non-smoking rides so the rest should either write it in a comment field or edit the ride afterwards to mark is specifically as “smoking”. So in this case we just removed an option from our wizard to avoid clutter. Lovely.

The examples above should go for all defaults .. also stuff your marketing department would like to decide e.g. when a user creates an account and have to uncheck instead of check a “Subscribe to our daily, fancy, not-to-miss newsletter” box. Focus on pleasing your users by pre-selecting choices they probably are going to make themselves … follow the “don’t make me think” principle! It makes users happy and allow them to complete a task faster.

Using sensible defaults goes for any type of application you are creating being for web, mobile or desktop.

Universal builds for Mac App Store with Xcode

While working on Wallpapery, I had to do a universal build for both 32- and 64-bit. I expected I should simply set “Architectures” to “Standard (32/64-bit Universal)” but after approval in Mac App Store and user complaints I found out, I had missed a couple of steps.

To build your product for both 32- and 64-bit architectures (aka i386 and x86_64) you have to explicitly unmark “Build Active Architecture Only” and filter list of “Valid Architectures” to only list “i386 x86_64”

Configuration settings for a Release target for Mac App Store

I wasn’t aware of that so maybe others find this useful.

How to get display name from NSScreen

While working on Wallpapery I needed to get a given screens display name. There is no “displayName” method on NSScreen so I added a category to provide this functionality. Seems like others are looking for this too so I’m posting my code below.

NSScreen+DisplayName.h

#import 

@interface NSScreen (DisplayName)

- (NSString *)displayName;

@end

NSScreen+DisplayName.m

#import 
#import "NSScreen+DisplayName.h"

@implementation NSScreen (DisplayName)

- (NSString *)displayName {
    NSString *screenName = nil;

    io_service_t framebuffer = CGDisplayIOServicePort([[[self deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]);
    NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(framebuffer, kIODisplayOnlyPreferredName);
    NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];

    if ([localizedNames count] > 0) {
        screenName = [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] retain];
    }
    else {
        screenName = @"Unknown";
    }

    [deviceInfo release];
    return [screenName autorelease];    
}

@end

You need to include the IOKit framework in your project.

Enjoy.

UIModalPresentationFormSheet width and height for an iPad in landscape mode

In a recent application I was doing, I was designing an interface to be shown as a modal form sheet using setModalPresentationStyle:UIModalPresentationFormSheet. I searched the Apple documentation to find the exact dimensions of this sheet but it isn’t documented.

It only states “The width and height of the presented view are smaller than those of the screen and the view is centered on the screen. If the device is in a landscape orientation and the keyboard is visible, the position of the view is adjusted upward so that the view remains visible. All uncovered areas are dimmed to prevent the user from interacting with them.”

AuthenticationViewController *authentication = [[AuthenticationViewController alloc] 
    initWithNibName:@"AuthenticationViewController"
    bundle:nil];
[authentication setDelegate:self];
[authentication setModalPresentationStyle:UIModalPresentationFormSheet];
[self presentModalViewController:authentication animated:NO];
[authentication release];

If others are looking for the same information, I can tell its dimension in landscape mode is 540×620. I got this by looking at [view frame].size.

How to backup Redmine on Google Storage

If you would like to backup your Redmine database and files, you might to consider Google Storage as your backup location. It comes with a 100 GB free monthly usage.

First, you need to sign up for a Google Storage account if you don’t have an account already.

Once done, download and install GSUtil which is a command line tool, allowing you to manage buckets.

Paste the following script into a file called “backup_redmine.sh”

# required settings 
DB_USERNAME=''
DB_PASSWORD=''
DB_NAME=''
REDMINE_ROOT='' # e.g. /home/peter/rails/redmine.commanigy.com'
BACKUP_ROOT='' # e.g. /home/peter/backups (will be created)

# optional settings
GS_ROOT='gs://redmine-backup'
GS_FILENAME='backup_'`date +%Y%m%d`'.tar.gz'

echo 'Setting up directories'
mkdir $BACKUP_ROOT/redmine/db -p
mkdir $BACKUP_ROOT/redmine/files -p

echo 'Backing up database'
/usr/bin/mysqldump -u $DB_USERNAME --password=$DB_PASSWORD $DB_NAME | gzip > $BACKUP_ROOT/redmine/db/`date +%Y%m%d`.gz

echo 'Backing up attachments'
rsync -a $REDMINE_ROOT/files/ $BACKUP_ROOT/redmine/files/

echo 'Packing into single archive'
tar -czPf $GS_FILENAME $BACKUP_ROOT/redmine/

echo 'Creating bucket on Google Storage (if not already created)'
gsutil mb $GS_ROOT

echo 'Copying backup archive to Google Storage'
gsutil cp $GS_FILENAME $GS_ROOT

echo 'Cleanup by removing archive'
rm $GS_FILENAME

echo 'Backup complete'

You might want to apply execute rights to your script using

chmod +x backup_redmine.sh

And maybe even add it to your crontab to get daily backups

crontab -e

Then add this line

@daily FULL_PATH_TO_SCRIPT > /dev/null

That’s it.

Let me know if you improve this script.

Using vi for your simple, day-to-day editing needs

My favorite editor isn’t vi, but I’m still using it at least a couple of times each day. It’s a short two character command, it’s always available and it starts fast.

I have used it for decades and still, I only know these commands. I really don’t need to learn any others, contrary what some of my friends tell me.

Need to know

j = move down
k = move up
l = move right
h = move left
i = go into “insert” mode
= go into “command-line” mode
ESC = go out of current mode
x = delete character
wq! = save file and quit (when in command mode)
q! = quit (when in command mode)

Good to know

{number}G = goto line
yy = copy line
dd = delete line
p = paste line below
P = paste line above
r = replace character
A = go into “insert” mode and append to end-of-line
/ = go into “search” mode

That’s it .. you might want to check out variants of these commands e.g. “5dd” to delete five lines, “4yy” to copy four lines.

If you need a list of all commands, look up the index help page in the vim (you are probably using vim and not vi) documentation using:

: help index

Lesson learned: Put limits on anything you provide for free

With our ShoutSMS service, we provide three free sms credits just for signing up. We do this to allow new users to try our service, without having to buy initial credits, just after they sign up.

Denied

After initial launch, we almost immediately got people from India hitting our servers. They signed up, confirmed their number and tried to send overtaxed sms to various numbers. Because I had chosen an initial credit limit and a max cost limit on each sms, it was avoided. I know from my previous work at ZYB, that unlimited sms and unlimited cost/sms is not something you want to offer.

ShoutSMS does tracking of all sms messages sent to prevent fraud. Users are currently not able to see this statistic themselves, but we are working on adding this ability in a future update. This will allow users to track how many messages were delivered and to which country.

Think mass sms marketing is something your company could benefit from using? Sign up for an account now and try it out for free.

Marketing tip: Include link to your app in newsletters

I have registered on a lot of sites and opt-in for their newsletter to be notified of updates.

One thing bugging me is, when a site sends a great mail in their newsletter but doesn’t include a direct link to their web site. The mail is coming from their domain so it isn’t hard to guess but users are lazy!

Since I’m registered on too many sites to visit regularly, I probably do want to visit a site, if it contains exiting updates but I have to admit, that without a direct link, I might not go for a visit but just archive that mail instead. It’s a pity so I’m suggesting this template for all your newsletter posts.

Hi Peter [name of user, if known],

We have just updated our site with a cool new feature, allowing you
to Y while doing Z. It's amazing and magical. Boom. Read more about
this on our blog? [link to blog post, if available]

Visit us at thecoolapp.com [link to your site]

Kind regards,
[personal name or team code name]

--

This mail was sent to john@doe.com [email] because you signed up 
for thecoolapp.com [link to site]. Unsubscribe immediately, if you do
not wish to receive more updates from us [link to unsubscribe link].

These basic elements should be in any marketing mail you send. If you are using any tracking tool, such as CampaignMonitor, you will notice a lot of people actually clicking your main web site link.

Upgraded ShoutSMS from Rails 2.3.8 to Rails 3 in five minutes

Today I wanted to try how easy it would be to upgrade our existing ShoutSMS (pretty small) rails application from 2.3.8 to latest Rails 3 release candidate (currently rc3). Without taking our test suite into consideration it took around five minutes with help from the official rails_upgrade[1] plugin. This is fast, yes, but considering the size of this app and possible pitfalls I am not looking forward to upgrade our larger projects.

These are the basic steps to perform

  • Install rails_upgrade in my 2.3.8 project using “./script/plugin install http://github.com/rails/rails_upgrade”
  • Run rake tasks installed with plugin to check what steps are required with “rake rails:upgrade:check”
  • Run “rake rails:upgrade:backup” to backup some files which will be override shortly
  • Run “rake rails:upgrade:configuration >> upgrade_configuration”
  • Run “rake rails:upgrade:gems >> upgrade_gems”
  • Run “rake rails:upgrade:routes >> upgrade_routes”
  • Create new Rails 3 app above your existing one with “rails n .”
  • Check each of your files before overriding – not all are backed up with the backup task
  • Copy back in your changes and refer to the three “upgrade_*” files for updated configuration, gems and routes syntax

This did most of the work for me. I needed to patch a bit in my new “application.rb” file (e.g. replace RAILS_ROOT with Rails.root, RAILS_ENV with Rails.env, etc).

Notice, the rails_upgrade plugin might suggest to change “<% @object.each do |p| %>” blocks to “<%= @object.each do |p| %>” but I don’t see this should be done.

I needed to upgrade ActiveMerchant but it was a simple

$ gem update activemerchant

and then patch my Gemfile with correct version

gem 'activemerchant', '1.7.1', :require => 'active_merchant'

It was also needed to go through each ERb and update block helpers. Rake task “rake rails:upgrade:check” can be used multiple times to check if you’re near the end.

I had a couple of “f.error_messages” warnings as well. It’s suggested to install “rails plugin install git://github.com/rails/dynamic_form.git” but I made a partial instead to have complete control over my displayed error messages.

For more general upgrade tips & tricks you might consider viewing part 1, part 2 and part 3 of the “Upgrading to Rails 3” Railscasts series.