29 September 2012

Programs don't have to be ugly?

Developing WPF applications using the MahApps.Metro themes and controls is not just fun but beautiful. 

Just look at the Git client for windows. It is a joy to use.

17 August 2012

Keep it simple stupid

I just love a well executed idea. I sumbled across one such the other day while re-writing the currently shitty build/dist script at work, of course it was written in Python :)
sh (previously pbs) is a full-fledged subprocess interface for Python that allows you to call any program as if it were a function:
from sh import ifconfig
print(ifconfig("wlan0"))

Isn't it just beautiful!

9 May 2012

Internet Rule Number 36?

In the last few years I've realised that having the attitude that

It's easier to ask for forgiveness than it is to get permission.

is in in many cases the easiest way to get things done. This approach can save you oh-so many pointless arguments and typical corporate ass-covering meetings with people less interested with getting things done and more with their job title and feeling important.
Meetings!
I admire people that just get shit done.

I might not agree with their approach. I might even argue with them, but no one can argue with results!


Unoriginality
When searching for the original author of that comment above I discovered that it is attributed to the late Grace Hopper. A remarkable woman and a great speaker. I think the video below shows possibly one of the best ways to explain intangible concepts. Bring a prop.


5 March 2012

Your code sucks, let's fix it

I found this presentation by Rafael Dohms quite interesting. It has some radical blanket statements and highly objectionable points but also quite a few post publishing edits and corrections.

If you keep a cool head and just take this as it is, you might just learn something (or at least get a refresher). I'll be the first to admit that I did.

4 March 2012

Degoogling

Like so many others I feel it is time to wean myself off my dependency on Google for search. It may come as a no surprise to anyone how relying on a single source for information opens you up to significantly biased view of the world and is inherently dangerous to do unconsciously. Although my field of work does not strictly require me to present an unbiased view of matters, recent policy and privacy changes for Google products have made me realise how, on an unconscious level, I immediately turn to Google search when I need to look something up and how that can impact my online experience in seemingly unrelated systems.


Cold Turkey
So I thought my best course of action was to completely remove Google search as my default go-to search provider. To begin with I chose to try out Bing (as it is the only search provider that offers a similar range of products I use from Google, i.e. search and maps). I am still disappointed that I couldn't use Office365 for free for personal use (I'd even settle for ads) but it seems that suite is solely meant for business users (big mistake I think).

So first I had to identify where my searches were originating from. I identified the following three areas in descending order of importance:
  1. My keyboard launcher, Launchy
    This is by far the most common way that I perform search on my computers. Fast and efficient but has contributed to this mental association that search == google as I need to type in the first letter of the provider I want and then press tab to enter my search term.

     
  2. Browser's address bar
    As I am a heavy user of Google's Chrome browser it has become almost natural to just start typing what I want into the address bar and then either press enter to search directly or pick from the drop down list. This is such a natural thing to do that I do it in any browser I use.




     
  3. Browser's search provider box
    After I stopped using Firefox as much as I used to I've stopped using the search provider box as much. But I still occasionally press Ctrl+K and start typing when I find myself using Firefox now and again. Neither IE or Chrome have this box anymore.

     
  4. Navigating to the search providers website to perform search
    This I almost never do on my main computers but occasionally do when using my phone to search for things. It is slow and annoying

How Easy Is It?
The single biggest difficulty I see is to change my own behaviour and the association I've made with Google and search, it will be hardest for item 1 as I need to stop typing "g <tab> <search term>" and rather type
"b <tab> <search term>"

Not so hard it seems. But I soon realised how instinctive that "g" had become. Most of the time I had already typed it and pressed <tab> before I realised. So that is going to be a challenge to change. Item 4 is so painful to do anyway that I don't see it as a problem at all (although it would be more of an issue if I used the search button on my Android phone more).

The rest is just a matter of configuring the technology to do what I want it to it seems.

Imagine my surprise when the simplest tool to configure to use Bing by far was Google Chrome and the biggest disappointment and betrayer was my old friend Mozilla Firefox.


Google Chrome 18
Simple. Clicking the spanner/wrench icon in the upper right hand side of the browser window, choosing Settings and simply choosing "Bing" from the dropdown list under Search on the Basics tab.
Voilà, now all my searches through Chrome are directed to the Bing website.

Total clicks: 3
Annoyances: None


Microsoft Internet Explorer 9
Strictly speaking then no configuration is needed out of the box for this browser as it comes with Bing already configured as default. However that is also the only search provider it comes with by default. To install any other is more painful that I would have wanted.

IE'sCog Icon
But to choose a different provider it is necessary to click the cog icon in the upper right hand corner of the browser window

Choose Internet Options, clicking the Settings button in the Search section on the first tab. That opens the Add-ons window which allows you to choose a different search provider. I use the term "allows" in a very generous way as it is near to impossible to see at a glance how to use anything else than Bing. But it is there near the bottom left corner disguised as one of those hard to see links.

It annoyed me that they made it this hard to choose as it is obvious that this was a deliberate UI design choice of theirs, one that probably went through a lot of disccusion, refinement etc before being approved and implemented.

Total clicks: 9
Annoyances: Had to close and re-open the Add-on window for the new search provider to appear in the list and manually close all those windows I had opened. Choosing the provider requires you to open an additional browser window to select (plus an extra window opens to confirm settings for the provider after selecting it).

Edit: 
After digging around a little more my curiosity got the better of me and I clicked the little magnifying glass  icon that is present on the far right in the IE address bar. While this gives you convenient access to your browser history and favourites, I discovered that it also lists your search providers and gives you a quicker way to install a new one (step that completely bypasses all the windows mentioned in the previous method). Much much better and actually more clear what provider you're using than it is in Chrome.

The IE magnifying glass (kudos to whoever added the downward
pointing triangle as I would otherwise never have clicked it)

Lists all the provider you have installed and allows easy admin
Total clicks: 6 (2 if you already have the provider installed)
Annoyances: None apart from the aforementioned annoyance having to open a separate website to choose the provider.


Mozilla Firefox 10
"Et tu, Brute?" - Julius Caesar, on seeing his friend among the assassins.

Many know by now that Google made a large contribution (pay off?) to be and stay the default search provider for the Mozilla Firefox browser. The figures from their recent December 2011 deal are estimated to be around $1 billion dollars just to stay the default search provider for the next three years. That sure is one valuable instance of a textbox control.

However it seems rather straight forward to change the default providers, Firefox even comes installed with a choice of a few search engines as alternatives to Google. Simply clicking on the icon in the search providers box gives easy access to choose a different one

That is until you attempt to search directly from the address box!

After choosing Bing search I could not understand why all my address box searches still sent my search query to Google. There was nothing in the configuration section of the browser that hinted that the two boxes did not use the same setting and why one was using Bing as I requested but the address box refused to do as I asked.

It wasn't until I dove under the covers and opened up about:config (which is an advanced configuration system for the browser and not recommended for the layman user). There I discovered quite the jungle of configuration settings related to search in the browser. The one that interested me the most I highlighted in the screenshot below

Sneaky bastards!
Firefox still retains Google as the default search engine even though I've clearly chosen to use Bing as my search provider. Luckily it is relatively simple to change by double clicking on the browser.search.defaultenginename row and type in "Bing". Sorted, now address bar searching will use Bing as default. Bada <pun>! Still I feel this kind of behaviour is deliberately misleading and under-handed.

Total clicks: 2
Annoyances: Does not change provider for address bar search, only for advanced users to discover and change.

Edit: Apparently Microsoft made a deal with Mozilla to produce a special Firefox with Bing browser.

Opera 11
I admit that I don't use the Opera browser on my computers all that much (almost never). However Opera is the only browser I use on my Android phone and it is simply brilliant there. But on desktop systems there are just to many alternatives that are better and sadly they have copied so many things from Firefox (or vice versa) that it just seems redundant to use when I already don't want to use Firefox.

Opera however suffers from a similar problem as Firefox, namely the disconnect between the search provider chosen in the provider box and the one that is used in its main address box. In addition Opera adds on yet another layer of confusion by adding the third search variant on their Speed Dial startup page.

These three boxes can all be set to different search providers. Confused?
Setting the default search engine to use is also not very straight forward as it should be. Same as with Firefox changing the search provider in the search provider box at the top right has no effect on either the address bar (still points to Google) or the Speed Dial box. You need to click the Opera button in the top left corner, choosing Settings and Preferences. Choose the third tab Search in that window and you are presented with a list of all configured search providers for the browser.
Editing the Bing Search Provider in Opera
To set the default search engine you need to double click the entry you want to set (Bing in this case) and click the "Details" button. Then tick the "Use as default search engine". Here you can also control the rather confusing Speed Dial search, reasons why you would want that different from your default one escape me.

Total clicks: 7
Annoyances: Obscurity and the disconnect between address bar and default search provider. Also the Speed Dial page is just plain confusing. But at least you don't have to dive under the hood to change these settings.


Conclusion
The technology can be changed easy enough (if you know where to look). But changing the learned behaviour is going to be harder, but I will give Bing an exclusive try for the next month.

This difficulty with Google in Firefox especially knowing how much Google is paying them for the install defaults feels like a sad regression back to the late 1990s when Microsoft was throwing its weight around in a similar manner bullying itself in a position to dominate the same market. I thought that showed clearly that all that got them was a lot of bad blood and eventually the involvement of US and European authorities when it became obvious to even the non-techies as they were clearly abusing their dominant market position to stifle competitors.

Perhaps moves such as these are the early indicators that the great cosine wave of technology firm's path to success has reached its maxima and has slowly but surely started its inevitable fall from grace. But I guess that might be better saved to a later post.

25 February 2012

Bing Linking and Internet Anonymity

This last Wednesday (22. Feb) the people behind the Bing search engine announced a rather big feature, Bing Linked Pages. This feature integrates your Facebook profile to the Bing search experience in a much more visible way than before.

Although "likes" made by friends have been used in the past by Bing to influence the search results you're served, Linked Pages might be far more jarring due to how much more in-your-face the "we know who you are" factor is than before.

Forever Archived
I like the general idea to give people a little more control over their digital identity than they currently have. It is a bit crazy that in an age where nothing about our life will be forgotten ever again and whatever stupid photo, silly comment or posted text will forever more be indexed and available within milliseconds as a part of our digital persona, that we cannot have even the slightest control over any of it.

So the much hyped Web 2.0 today pretty much boils down to you either posting something as your official digital persona and then be ready to face the consequences of that perhaps 20 years down the line or opt for complete anonymity. Why do we need these absolutes? I like neither.

I think it is every ones basic right as the fallible ever-evolving humans we are to have the right to change our minds, form different opinions or change our behaviour patterns. Think this is what is basically happening when we grow up, become adults, go on a diet etc. The fact that we still have to lug around with us (and this applies more to the younger >25y generation than me) our entire history for anyone to recall or browse through is in short frightening.

Linked Pages could have been so much more
But back to Bing, so that is why my first reaction to the Bing Linked Pages was an overall positive one. The idea is great. But it seems that the realisation is however not. Below are a few things that bother me about this particular implementation:
  1. Requiring Friend Status To See a Person's Linked Pages: In all seriousness do you really need yet another profile in addition to your Facebook one? This new Linked Pages feature is apparently only visible when the person searching is logged into Facebook on Bing and is currently registered as a friend of the person they're searching for.

    This sounds to me just a duplication of the existing profile system in Facebook which is already quite extensive and most people put quite a bit of thought into these days. If you're searching for your Facebook friend's name on a search engine it is fairly likely that you do not want information already available to you in Facebook.
     
  2. Facebook Timeline Integration: Bing's choice of Facebook Connect as a sign-in ID makes a lot of sense (rather than requiring you to sign up for a LiveID). The FC user-base is huge and the process can be completed in under three clicks. However the decision to make it necessary to allow the Linked Pages feature app to post to your timeline is beyond me.

    Why does this otherwise great way to make sure that people find relevant information about you when you are "binged" (is that a verb yet?) have to have any ping-back communication or linkage with your Facebook profile? Remove this silly posting restriction, it makes no sense that Bing needs to post anything to your Facebook (optional is fine).

    To be fair: you can delete individual postings from your timeline after the fact. But it quickly becomes annoying as other friends of yours start linking pages to you. Which brings me to...
     
  3. Allowing Friends to Link Pages to You: Now this makes absolutely no sense to allow. Why would anyone want anyone other than themselves to control or influence their outward online persona? This single point completely defeats the purpose of the whole Linked Pages feature as we're back into the land of uncertainties where you're hopelessly dependent on outside factors to direct this aspect of yourself.

    Facebook already has a way for your friends to post to your timeline on Facebook why would you want to essentially create the same thing again on Bing? I think very few of us on Facebook have a completely separate accounts and rather opt for controlling friends access to information through groups or simply just let everyone see everything. Which brings me to...
      
  4. Not Every Friend on Facebook is Your Friend: aka not every friend on Facebook can be trusted. The fact is that if you're anything like me you have people on Facebook from all walks of life and for a variety of different reasons. Real-life friends, family, extended family, old school buddies, current and former work mates and bosses, current and former partners of friends, people you've met travelling, in the pub, on a boat, in a plane, you name it.

    You would not necessarily want to trust them all with your search result profile. Especially since it is becoming increasingly common that peoples' names get binged/googled by prospective employers, when applying for mortgages or loans, applying for adoption and countless other reasons.
  5. Unhelpful, Borderline Arrogance Towards Users: While you might want to allow your friends to post to your already locked off Facebook wall, you might not want them to influence your public search results without supervision. Perhaps it is just me but I like to joke around with some of my friends and different groups of people have different kinds of humor. Some of the jokes are very much in-jokes, which quite often surface as Facebook wall posts, comments and likes.

    But as everyone that is allowed to post on your wall can use the Bing Linked Pages to link you to a page you might see how this could become a little bit problematic when dealing with your joker friends (as well as them dealing with yourself).

    Providing ridiculous suggestions such as the one below, should never ever ever ever be a part of the Bing team's response. When playing the role of the underdog, this kind of borderline "take-it-or-leave-it" attitude is not acceptable. Bing should humbly want their users to adopt their technology. You're asking people to give their time into something collaborative which will provide Bing with heaps of valuable information. Treat it as you would a present not like this:
    If a friend keeps linking you to pages that you don’t want associated with you, you can't prevent the friend from doing it again as long as they're a friend, but you can unfriend them, and then remove the links.

I Want Bing To Succeed
Don't get me wrong, I am rooting for the Bing group to become wildly successful and for the Bing search engine to provide a viable alternative to the Googlelith. Partly because Bing is the underdog in the competition. But also and more importantly because a lot of us don't realise the wool that has been pulled over our eyes with regard to the so called "features" and "freebies" that the G offers us (the hypocrisy is not lost on me, me writing this on Blogger, don't worry).

But as real life is fast clashing with the naive Google idealism of doing no evil more of the general public will hopefully catch on that they're only getting these so called freebies because they are indeed Google's livestock being raised and sold.

But Bing, you have to do more than just match G, make search different!

... maybe I should jot down some ideas (stay tuned)

24 February 2012

Why I Think C# and Java Trump C and C++

Well the title is a bit sensationalist. As a disclaimer I strongly believe that you need to pick the correct tool that best suits the job at hand and that you believe you will be the most productive in.

However when faced with the agonizing task of printing out Trace messages with variable formatting in a bit of C code that I had lying around recently, I realised just how focused C# is on getting things done rather than faffing about with boilerplate code.

As an example, here are two functions that fundamentally do the same thing, print a formatted string to the system Trace listeners using a single format string and then a variable number of arguments:

First the C# function:
void odprintf(string format, params object[] args)
{
    Trace.WriteLine(string.Format(format, args));
}

Compared to the C equivalent:
void __cdecl odprintf(const char *format, ...)
{
    char buf[4096], *p = buf;
    va_list args;
    int n;

    va_start(args, format);
                             // buf-3 is room for CR/LF/NUL
    n = _vsnprintf(p, sizeof buf - 3, format, args);
    va_end(args);

    p += (n < 0) ? sizeof buf - 3 : n;
    while ( p > buf  &&  isspace(p[-1]) )
            *--p = '\0';

    *p++ = '\r';
    *p++ = '\n';
    *p   = '\0';

    OutputDebugStringA(buf);
}
Really, all this magic is necessary to just print to Trace?

I reserve the right to seriously doubt that "lower" level languages have any place but in highly specialised or those extremely few cases where throughput and latency are more important than developer productivity and deadlines are lax and forgiving.

Here is someone that is more eloquent than I am on this issue.
There is no reason to use C++ for new projects. However, there are existing projects in C++ which might be worth working on. Weighting the positive aspects of such a project against the sad fact that C++ is involved is a matter of personal judgement.

If you end up working with C++, don't try to "fix" it (or "boost" it). You'll just add more layers of complexity. The most productive approach is to accept the problems and try to write simple code which people can easily follow.

If you are an expert in the intricacies of C++, please consider this knowledge a kind of martial art - something a real master never uses.

23 February 2012

Calculating Combinations of 1, 2, 3 Step Jumps

So again I was trolling along on Antonio Gulli's website (which has become a bit of a favorite to find fun problems to solve during a quiet evening). I came across this question:
A child can hop either 1, 2, or 3 steps in a stairway of N steps.
How many combinations do you have?
As the first comment mentions then this problem can be solved using recursion. But the question is, how would you translate this into program code?

... want a second to think about this before reading my attempts?

Initial Attempt
After thinking about this problem for a little while I decided that this might be cleanly solved using a recursive tree traversal algorithm. As we have a branching factor of 3 we should not have a branch height of more than N/3 (only taking 3 step jumps) in the best case and N in the worst case (if only taking 1 step jumps).

The initial naive solution I came up with was a simple DFS search using a stack (LIFO):

static Stack<long> nodes = new Stack<long>();
static long Combinations( int n )
{
    long leafs = 0;
    nodes.Push(n);
    while (nodes.Count > 0)
    {
        var x = nodes.Pop();

        // Leaf, just count
        if (x <= 0) leafs++;
        else
        {
            // Only push down options where the child 
            // can actually complete the stair jump
            if (x - 1 >= 0) nodes.Push(x - 1);
            if (x - 2 >= 0) nodes.Push(x - 2);
            if (x - 3 >= 0) nodes.Push(x - 3);
        }
    }
    return leafs;
}

Improved Attempt
It is soon obvious if you run the first code using non-trivial sizes of N that this naive DFS solution is simply too slow. The time that it takes to iterate through the entire tree and generating all the intermediary nodes is just too great and quite quickly the algorithm takes too long to return a solution within a reasonable time.

When you look closer at this ternary tree it might become obvious that since it is a complete tree it has a simple repeating pattern down each of its branches. Basically each branch is a sub-tree of the one preceding it (with node count n-1). Meaning that the (n-1) branch far to the left at height h has an equal amount of nodes in its immediate (n-1) child at h-1 as the second (n-2) branch at h has.

Using this we can simply pre-cache each height in the tree once we have calculated it completely and thus really only need to do one full depth run on a single branch after which we will have all the necessary values calculated for the remaining nodes.

           A
          /|\
         B C D
        /|\
       E F G
      /|\
     H I J
We only need to calculate the A,B,E,H values, after that no extra recursive traversal is necessary into any other subtrees as we can use the cached value for H for F, J for G, E for C, F for D and so forth.

So by adding a simple map that caches the node count for every remaining node number we can significantly speed up this calculation:

static Dictionary<int, BigInteger> map = new Dictionary<int, BigInteger>();
static BigInteger Combinations2(int n)
{
    if (n <= 0) return 1;

    BigInteger leafs = 0;
    if (map.TryGetValue(n, out leafs))
        return leafs;

    // We need to calculate it if not found
    if (n - 1 >= 0)
        leafs += Combinations2(n - 1);
    if (n - 2 >= 0)
        leafs += Combinations2(n - 2);
    if (n - 3 >= 0)
        leafs += Combinations2(n - 3);

    map[n] = leafs;
    return leafs;
}

We can probably do better than this though?

19 February 2012

Symphony of Science

This video still gives me goosebumps every time (the only acceptable use of auto-tune):



And if you haven't watched Jill B. Taylor's TED talk about her first hand experience of how it feels like having a massive brain stroke you should do so now.

18 February 2012

geeksforgeeks.org

This one is a fun read geeksforgeeks.org, try solving a few of the programming problems before reading the articles/solutions.

It is fun, I guarantee it :)

Also they have a good interviewing section, just don't get too hung up on it mkay

The absolute difference between two double numbers

How would we create a function

      abs( double a, double b )

that returns the absolute value of the difference between a and b?

Edit 21/02/2012:
I embarrassingly have to admit that before posting this entry in the beginning I had spent about an hour attempting some fancy prancy bit masking solution (as one might do in a integer or long abs function) gazing at bit arrangements and getting myself into an utter dead end and 100+ lines of code. I decided that this might simply be the best solution I could come up with:

public static double abs(double a, double b)
{
    double diff = b > a ? b - a : a - b;
    return diff < 0 ? -diff : diff;
}

Too stupid to fail?

17 February 2012

Bit manipulation gasp, gasp

Call me an elitist if you want, but it still surprises me how reluctant programmers are to use basic bit operations.

As an example, let's say that you have a series of calls to functions that might return true or false and you want to call every single one of them but if one of them returns true you want to preserve that value at the expense of the other false values.

For such a problem I am more likely to encounter code written similar to this:
bool anyreturntrue = false;
for( a few calls )
{
    bool result = SomeFunction();
    if( !anyreturntrue && result)
        anyreturntrue = result;
}
return anyreturntrue;

rather than the more elegant:
bool anyreturntrue = false;
for( a few calls )
    anyreturntrue |= SomeFunction();
return anyreturntrue;

Should this really be considered wizardry?
I hope not.

Learning about it makes it better somehow

Stuck on or waiting for the Tube in London?

Hearing the disembodied electronic woman's voice droning on about a "Signal failure"?

Yearning to know more?

16 February 2012

Calculating x^y

I stumbled onto this blog (Antonio Gulli) the other day and read through a couple of his suggested programming problems.

Kind of interesting to tackle that power function. After coming up with a rather naive solution to begin with, I attempted to improve on it and ended up with the following implementation for X^Y that works when X and Y  are integers. As I wanted to keep it rooted in the .NET framework implementation I needed to use the BigInteger class so the function will not return a value for negative Y values just yet :)

What do you think?

using System;
using System.Numerics;

internal class Program
{
    private static void Main(string[] args)
    {
        int x = 2;
        int y = 2000;

        BigInteger pow = Pow(x, y);

        Console.WriteLine("{0}^{1}={2}", x, y, pow);
    }

    private static BigInteger Pow(int x, int y)
    {
        if (y == 0) return 1; // Zero power
        int ay = Math.Abs(y);
        BigInteger pow = 1;
        BigInteger sum = x;
        if (ay > 0)
        {
            var iterations = (int) Math.Ceiling(Math.Log(ay, 2));
            for (int i = 0; i <= iterations; ++i)
            {
                if (ay == 0) break;
                if (ay%2 != 0) pow *= sum;
                sum *= sum;
                ay = ay/2;
            }
        }

        // Handle negative powers (Well this will work when we have BigDecimal in System.Numerics)
        return y < 0 ? 1/pow : pow;
    }
}

15 February 2012

What are we, five?

If you wear this badge, I have no respect for you :/


14 February 2012

GPS points of all bus stops in London

Hope I am not the only one this happens to.

Dream of building the greatest app ever, come up with a decent enough idea, research the available technology to build it and the data needed. Even gather said data and work on converting it to a suitable format. Then realise that it is 5am and you need to get up for work in the morning. 

Anyways, in hopes that I help someone else out there kickstart their project. Here is a handy way to download the entire TFL london bus network, every route, GPS coordinates of every stop right to your doorstep.

1. Download cURL here.
2. Run the following commands 
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={1,10,100,101,102,103,104,105,106,107,108,109,11,110,111,112,113,114,115,116,117,118,119}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={12,120,121,122,123,124,125,126,127,128,129,13,130,131,132,133,134,135,136,137,138,139,14}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={140,141,142,143,144,145,146,147,148,149,15,150,151,152,153,154,155,156,157,158,159,16,160}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={161,162,163,164,165,166,167,168,169,17,170,171,172,173,174,175,176,177,178,179,18,180,181}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={182,183,184,185,186,187,188,189,19,190,191,192,193,194,195,196,197,198,199,2,20,200,201,202}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={203,204,205,206,207,208,209,21,210,211,212,213,214,215,216,217,219,22,220,221,222,223,224,225}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={226,227,228,229,23,230,231,232,233,234,235,236,237,238,24,240,241,242,243,244,245,246,247,248}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={249,25,250,251,252,253,254,255,256,257,258,259,26,260,261,262,263,264,265,266,267,268,269,27}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={270,271,272,273,274,275,276,277,279,28,280,281,282,283,284,285,286,287,288,289,29,290,291,292}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={293,294,295,296,297,298,299,3,30,300,302,303,305,307,308,309,31,312,313,314,315,316,317,318,319}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={32,320,321,322,323,325,326,327,328,329,33,330,331,332,333,336,337,339,34,340,341,343,344,345,346}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={347,349,35,350,352,353,354,355,356,357,358,359,36,360,362,363,364,365,366,367,368,37,370,371,372}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={375,376,377,379,38,380,381,382,383,384,385,386,387,388,389,39,390,391,393,394,395,396,397,398,399}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={4,40,401,403,404,405,406,407,41,410,411,412,413,414,415,417,418,419,42,422,423,424,425,427,428,43}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={430,432,434,436,44,440,444,45,450,452,453,455,46,460,462,463,464,465,466,467,468,469,47,470,472}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={473,474,476,48,481,482,484,485,486,487,488,49,490,491,492,493,496,498,499,5,50,507,51,52,521,53}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={54,549,55,56,57,58,59,6,60,601,602,603,606,607,608,609,61,611,612,613,616,617,62,621,624,625,626}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={627,628,629,63,632,634,635,639,64,640,641,642,643,646,647,648,649,65,650,651,652,653,654,655,656}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={658,66,660,661,664,665,667,669,67,670,671,672,673,674,675,678,679,68,681,683,685,686,687,688}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={689,69,690,691,692,696,697,698,699,7,70,71,72,73,74,75,76,77,78,79,8,80,81,82,83,85,86,87,88}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={89,9,90,91,917,92,93,931,94,941,95,953,958,96,965,969,97,972,98,99,A10,B11,B12,B13,B14,B15,B16}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={C1,C10,C11,C2,C3,D3,D6,D7,D8,E1,E10,E11,E2,E3,E5,E6,E7,E8,E9,EL1,EL2,G1,H1,H10,H11,H12,H13,H14}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={H17,H18,H19,H2,H20,H22,H25,H26,H28,H3,H32,H37,H9,H91,H98,K1,K2,K3,K4,N1,N11,N13,N133,N136,N137}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={N15,N155,N159,N16,N171,N18,N19,N2,N20,N207,N21,N22,N253,N26,N279,N28,N29,N3,N31,N343,N35,N38,N381}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={N41,N44,N47,N5,N52,N55,N550,N551,N63,N68,N7,N73,N74,N76,N8,N86,N87,N89,N9,N91,N97,N98,P12,P13,P4}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={P5,PR2,R1,R10,R11,R2,R3,R4,R5,R6,R68,R7,R70,R8,R9,RV1,S1,S3,S4,T31,T32,T33,U1,U10,U2,U3,U4,U5,U7}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"
curl.exe "http://www.tfl.gov.uk/tfl/gettingaround/maps/buses/tfl-bus-map/dotnet/FullRoute.aspx?route={U9,UL1,UL2,W10,W11,W12,W13,W14,W15,W16,W19,W3,W4,W5,W6,W7,W8,W9,X26,X68}&run={1,2}" --create-dirs --output "busroutes\#1-#2.txt"