Category Archives: Software Development

Detect mobile browsers in server-side code

Last week I found myself needing to detect mobile browsers on the server-side and ran across this extremely useful site:

http://detectmobilebrowsers.com/

It offers open source code for doing just that. Many languages are available: C#, Ruby, JavaScript & node.js, PHP, Python, and more. Even Perl!

Often you’d use this code to redirect the user to a mobile version of your site. However, my site uses the responsive Twenty Twelve WordPress theme. This works well on mobile browsers. Thus, I don’t really want or need to redirect the user.

Unfortunately, there’s one particular piece of content that was banjaxxing the page width on mobile devices. It needed to be replaced. Normally I’d do this on the client-side, which is what the theme does. In this cases the content’s Ts & Cs meant I wasn’t allowed to. But I could do it on the server.

You probably know that you can’t get the client’s screen resolution or browser window dimensions on the server. However, you can use the user-agent string to detect mobile browsers. This is exactly what the code at detectmobilebrowsers.com does. They’ve written and tested code that will reliably detect mobile browsers across most devices. That isn’t something I wanted to attempt myself (how would I test it?), and neither should you.

WordPress runs on PHP so I now have this particularly minging, but highly functional, lump of code in one of my template scripts:

<?php
$useragent=$_SERVER['HTTP_USER_AGENT'];
if(preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',substr($useragent,0,4))) : ?>

    <div style="padding-bottom: 16px; margin-left: -24px; margin-top: -24px;">
        <!-- Content displayed on mobile (but not tablet) browsers here -->
    </div>

<?php else : ?>

    <span style="float: right; clear: right; padding-bottom: 8px;">
        <!-- Content displayed on all other browsers here -->
    </span>

<?php endif; ?>

DO NOT copy this code. New devices are being released all the time so make sure you grab the latest version from detectmobilebrowsers.com. That way your code will work with the most recent generation of devices.

To edit your WordPress templates just open up your dashboard and click Appearance > Editor:

Edit WordPress templates.

(Oh, and if I ever need that check in more than one place I’ll refactor it into a method. For now I can live with it sitting in the one template where I need it.)

As my comment in the code suggests, this won’t work for tablets. If you need special support for them, add the code snippet under the Tablets section here to the first regex. You can also separate the checks for mobiles and tablets, or even different models of mobile/tablet, if you need more fine-grained control over site behaviour.

Speaking on Node Tools for Visual Studio at Node.js & JavaScript Cambridge Meetup

I’m pleased to say I’ll be speaking at the Node.js & JavaScript Cambridge meetup on Tuesday 8th April. It’s upstairs at the Fountain Inn on Regent Street in Cambridge (UK), starting at 7.45PM.

I’ll be talking about and demoing Node Tools for Visual Studio. If you want to learn how to develop for Node on Windows, and you’re in the local area, please do come along. You can already sign up at:

http://www.meetup.com/NodeJS-Cambridge/events/164845272/

There will be two talks during the evening. I’m not sure what the other one is yet, but I’ll post as soon as I know. The usual format is 20 minute talks with 10 minutes at the end of each for questions.

I’m going to try to cover:

  • The different project templates
  • npm
  • Editing
  • Debugging
  • Profiling
  • Azure deployment

That’ll probably more than fill 20 minutes without too much difficulty. Being Cambridge, people love to ask questions so we’ll see if I can get through it all or not!

As I say, if you’re in the area that night, please do come along. They’re a sociable crowd and there’s plenty of time for drinking and chatting afterwards.

C# quick tip: does exception handling work with async method calls?

The short answer is, yes… but.

Say you’ve defined some async method:

public async Task<bool> MyAsyncMethod() {

    // Location A: some code here

    var result = await SomeOtherAsyncMethod();

    // Location B: some more code here

    if (someCondition) {
        throw new SomeException();
    }

    return result;
}

How can you call MyAsyncMethod in a try-catch block so you can catch SomeException?

Here’s what you DON’T do:

try {

    // Location C: yet more code here

    MyAsyncMethod();

    // Location D: and even more code

} catch (SomeException ex) {

    // Location E: exception handling code

}

The problem is the call to MyAsyncMethod (highlighted) doesn’t await its return. As soon as MyAsyncMethod has finished executing the code at location A and hits the line that calls SomeOtherAsyncMethod, control returns to the code after the call to MyAsyncMethod (location D). It then passes out of the try-catch block before the code at location B has chance to execute.

Thus, if SomeException is thrown, it won’t be caught. Since there’s now no handler for it, your app is going down…

Oops, something's gone wrong.

(The specifics of what actually happens will depend on the type of app and, sorry desktop IE, I don’t mean to pick on you.)

To catch the exception, you need to await the return of MyAsyncMethod:

try {

    // Location C: yet more code here

    await MyAsyncMethod();

    // Location D: and even more code

} catch (SomeException ex) {

    // Location E: exception handling code

}

Or, if you need its return value:

var result = await MyAsyncMethod(); // etc.

Either way control will not return to your calling code, continuing at location D, until MyAsyncMethod has completed. If MyAsyncMethod throws SomeException, it will be caught and handled by the code at location E – as expected.

IMPORTANT: there is no blocking here so your app will not become unresponsive whilst MyAsyncMethod runs.

There’s a lot of compiler magic* The compiler does a lot of work for you to ensure this works seamlessly. It also uses some support types in the framework itself. This means you can keep your code nice and straightforward.

If you’d like to know more about how async compilation works, check out http://weblogs.asp.net/dixin/archive/2012/11/02/understanding-c-async-await-1-compilation.aspx.

*It’s clever, but it’s absolutely not magic. Rather, it’s awesome engineering.

Git basics: how to merge changes from a different fork into your own branch

If you work with git, especially with either GitHub or CodePlex, you’ll commonly need to merge from branches in a different fork into your own branches in your own fork.

A typical scenario is you’ve forked a repo, made some changes, and now you want to send a pull request to get your changes into the original repo. Of course, not many people will accept your pull request unless you first merge their latest changes into your code – it’s only polite, after all!

At first this can seem daunting but, once you’ve done it a few times, it’ll become second nature.

The method I’m going to show you isn’t necessarily the quickest or most efficient under all circumstances but it’s reliable and, most importantly, if you make a mistake you won’t lose any work. When you use git (or any scm) sooner or later you’ll screw something up. Everybody does: don’t worry about it. If you’ve taken precautions, it won’t matter, so you should feel free to experiment and learn. In the worst case you can always blow away your local repo and do a fresh clone from your remote.

Anyway, back to our merge. There are three stages to the process:

  1. Prepare so that if something goes wrong (it shouldn’t) you can get your local repo back into a consistent state.
  2. Merge changes from the branch on the other fork into your local branch.
  3. Push those changes to your fork’s remote branch (optional).

I’ve broken the first two stages down into quite a few steps, but don’t worry: they’re all simple, and the whole process really doesn’t take very long. Like I say, it’ll quickly become second nature.

1. Prepare

The purpose of this is to ensure that, if anything goes wrong, you can get back to a repository in a consistent state without losing any of your own changes.

  1. If necessary, switch to the branch you want to merge into (make sure you’ve committed or stashed any changes on your current branch first!) with:
    git checkout <branch_name>
  2. Firstly, check if you have any local changes. Make sure you’re in a folder somewhere in your local repo and execute:
    git status

    This will tell you about any changed, new, or deleted files.

  3. Now stage any modified files for commit (you can obviously skip this step if there aren’t any):
    git add <path_to_file_1> <path_to_file_2> ...

    You can also use wildcards:

    git add *.cs *.js

    BE CAREFUL with this. You can inadvertently add a lot more than you intend! If that does happen you can unstage any erroneously staged files with:

    git reset HEAD <path_to_file_1> <path_to_file_2> ...

    If you’ve accidently added loads of files you’ll probably find it easier to use the same wildcards to unstage the lot, before adding the right files individually:

    git reset HEAD *.cs *.js

    Don’t worry: you WILL NOT lose uncommitted changes: you’ll just change the status of these files from staged back to modified/added/deleted.

  4. Commit your changes locally with:
    git commit -m "Write your commit message here."
  5. Pull any changes from your own remote:
    git pull
  6. Manually merge any conflicts that git couldn’t auto-merge. I use Scooter Software’s Beyond Compare for this, but you can use whatever tool you like. I used to be a fan of WinMerge but have recently run into problems with it. YMMV.
  7. Build your code, and fix any errors.
  8. Run your tests, and fix any failures.
  9. Commit any changes you’ve made locally again (git status, git add …, git commit -m …).
  10. If you’ve had to spend much time on the last four steps: pull, build, and run tests again (fix any problems and commit your changes again, obviously).
  11. Push changes to your remote repo:
    git push

    All your changes are now safe and, if something goes wrong, you can just clone again from your remote repo with:

    git clone <remote_repo_name>

    If you don’t want to push changes to your remote repo you can just create a copy of your local repo in a separate folder using Windows Explorer, or from the command line. You can of course try to fix your local repo using git commands but, unless you’re very experienced, there’s a good chance you’ll make matters worse. If you’ve created a backup this doesn’t matter: go ahead and use git to try to fix any problems so that you’ll become more competent with it and, if it doesn’t work, just rename your banjaxxed repo folder and copy your backup back into place. If you don’t have time to mess around just do the rename and copy.

2. Merge

This is where the fun begins.

  1. First we need to add the other fork as a remote for your repo.
    git remote add <remote_name> <fork_url>

    <remote_name> is just the identifier you will use when referring to the remote – essentially it saves you from having to type out the entire fork URL each time. For example, ms11022014.

    <fork_url>, as you may have guessed, is the URL for the fork’s repo, e.g., https://git01.codeplex.com/forks/bartread/ms11022014.

  2. Now verify the remote using:
    git remote -v

    You should see some output similar to this, with both a fetch and a push line for your new remote:

    ms11022014 https://git01.codeplex.com/forks/bartread/ms11022014 (fetch)
    ms11022014 https://git01.codeplex.com/forks/bartread/ms11022014 (push)
    origin https://git01.codeplex.com/forks/bartread/rgnpm01 (fetch)
    origin https://git01.codeplex.com/forks/bartread/rgnpm01 (push)
  3. Fetch the branches and commits of the new remote with:
    git fetch <remote_name>
  4. If needs be, switch to the branch you want to merge into, with:
    git checkout <branch_name>
  5. Merge changes from the required remote branch:
    git merge <remote_name>/<remote_branch_name>

    For example, to merge from the above remote’s master, I’d execute:

    git merge ms11022014/master
  6. Check git’s output for conflicts and manually resolve any you need to, as in Prepare step 6.
  7. Build your code, run tests, and fix any errors/failures, as in Prepare steps 7 and 8.
  8. Commit any changes to your local repo with git status, git add …, and git commit -m …, as in Prepare steps 2, 3, and 4.

3. Push

If you’ve got this far the hard part is over: you’ve merged changes from a branch in the remote fork into one of your own local branches, and committed them to your local repo.

That might be all you need to do at this point. If you do need to push changes back to your own remote fork (most likely, origin), just execute:

git push <remote_name> <branch_name>

So, to push changes from master back to origin, I’d execute:

git push origin master

And you’re done!

Help! It’s all gone horribly wrong! What do I do?

If you followed my advice in the prepare stage you can just “restore from backup” (if you didn’t, I’m afraid you’re on your own):

  1. Rename your local repo directory.
  2. Either clone your remote repo again (use git clone <remote_repo_url> from the command line), or copy (don’t move!) the backup of your local repo that you created in a separate folder back into its original location.
  3. Verify that your cloned or copied repo is in a good state (e.g., build your code, run tests).
  4. Delete the old local repo directory that you renamed.

Now you can try again.