Other articles

  1. Lost in Localisation - Ordering a Taxi while on Holiday

    I was on holiday in England this summer. I arrived in Worthing by bus from London, had a full day there, and wanted to take the train the following day to Bristol. The bus route from my BnB to the station was inconvenient and expensive. Ordering a taxi was my next idea. I wanted to do that without human interaction the evening before. This is the story of how that did not work.

    I name the taxi company in this article. This is not to shame them. I hope they just fix the issues, which I believe present in many applications, because localisation is hard.

    Website screenshot promising easy access via mobile app

    Quite a Promise

    The Mobile App

    Before analyzing why ordering a taxicab through their website did not work, I wanted to try the mobile app. I was hopeful, considering their promise that I could "book a car in seconds and don't even need to ring us!".

    As it turns out, this app is not available through the German Google Play Store. This means, you won't find it when you search for it and if you have the correct URL, you can't install the app through the web interface on a device that is connected to the German Google Play Store (so all of mine).

    But this is not a problem since you can download any APK that is available from any app store through a third-party service like APKPure (unendorsed). So knowing the name of the app in the Play Store I did that and installed the app.

    Screenshot of the app

    That is the App

    You're presented with a registration screen where you have to enter your phone number to receive a confirmation SMS. My (international) phone number didn't take and I was not able to complete the process. We will later see why. Being unable to register via the app, I return to the web site.

    Screenshot of the website

    The website looks quite modern

    The Web Site

    Order Form

    The first part of the order form

    As you can see, to order a taxi you first have to enter where you want to be picked up and where you want to go. The system then calculates the distance between both points, estimates the cost, and then you can go on to the next step.

    In order to calculate the distance, the web site uses the Google Maps API to create a route between both points and calculates a cost. Here's the corresponding code from the site:

    journey['distance'] = response.routes[0].legs[0].distance;
    journey['duration'] = response.routes[0].legs[0].duration;
    journey['miles'] = ( journey['distance'].value * 0.000621371192 );
    journey['price'] = CurrencyFormatted(2.90);
    journey['total'] = CurrencyFormatted( journey['price']
                                  + 1.90 * ( journey['miles'] - 0.2 ));
    journey['start_address'] = response.routes[0].legs[0].start_address;
    journey['end_address'] = response.routes[0].legs[0].end_address;

    This looks okay. It is to note that the site takes the addresses returned by google as the canonical start and end of the journey. So in principle, you could enter the name of a shop or restaurant as the target location of your taxicab ride and as long as google knows it, the taxi service is booked to the actual and correct address.

    Then there's another step of validation: Since the taxicab company only operates in Worthing in the south of England, they do not want to accept rides that are outside a specific area. They want to achieve this by parsing the post code from the canonical google response and compare it to a set of given post codes that correspond to the Worthing area: journey['start_postcode'] = journey['start_address'].match(/([A-Z]?\d(:? \d[A-Z]{2})?|[A-Z]\d{2}(:? \d[A-Z]{2})?|[A-Z]{2}\d(:? \d[A-Z]{2})?|[A-Z]{2}\d{2}(:? \d[A-Z]{2})?|[A-Z]\d[A-Z](:? \d[A-Z]{2})?|[A-Z]{2}\d[A-Z](:? \d[A-Z]{2})?),\s*UK$/)[0]. That's quite a large regular expression and I give you a visualisation powered by Regexper:

    Visualisation of the regular expression

    This does correspond in some fashion (but not exactly [1]) to the valid UK post codes followed by ", UK" and the end of the input.

    I give you part of the google response for a ride between some random house and the train station and let you figure out why this step fails for me:

    { "routes" : [
          { "legs" : [
                   "distance" : {
                      "text" : "1,7 km",
                      "value" : 1654
                   "duration" : {
                      "text" : "5 Minuten",
                      "value" : 292
                   "end_address" : "Worthing BN11 1AA, Vereinigtes Königreich",
                   "start_address" : "Harrow Rd, Worthing BN11 4RB, Vereinigtes Königreich"

    Google does return the post code correctly, but since my browser is set to German, Google's response is in German as well. The regular expression only matches strings ending in "UK", while my German response ends in "Vereinigtes Königreich" ("United Kingdom" in German).

    The fix seems easy enough. Just set the browser language to UK English and do the whole thing again and there we go:

    Form containing the quote of about 6 pounds


    Final part of the booking form asking for the name and phone number

    Okay, good. Let's book the taxi.

    Now we just have to enter our name, email address, and phone number and we're good and finally can go by taxi wherever we want to go (within the greater Worthing area). As I enter my phone number, starting with +49 or 0049 for Germany, followed by three digits for the service provider [2], and seven or eight digits for the user, it dawns on me that it might not be that easy (as if it had been up to this point) and I take another glance at the code:

    function validateTelephone(telephone){
      var re = /^(?:\W*\d){11}\W*$/;
      return re.test(telephone);

    Oh oh. Okay. Yeah. About that...

    My phone number does not fit that scheme (while 00000000000 does). If I get any confirmation code I need to respond to, or they want to call back for some additional questions, they won't be able to reach me. This is probably also the reason why the app did not work and why I couldn't receive an SMS with a confirmation code.

    I won't be able to order a taxi online. To recap the two main reasons why:

    • Because my browser is set to something else than English, the website can not verify that the cab journey takes place within the serviced area. Solution: Google provides GPS coordinates for the legs of the journey. One can easily check whether they are contained within a rectangle or convex polygon.
    • Because I have an international phone number, I can't interact with the parts of the process that depend on my cellphone. Solution: Allow for international phone numbers or make the process not depend on them.

    In the end I called them by phone, which took a whopping 25 seconds and the taxi arrived on time to bring me to the train station.

    [1]According to Wikipedia, the UK government has provided a regular expression that can be used for the purpose of validation: ^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$
    [2]It's a little bit more complicated but sufficient for this story.

  2. Upgrading Fedora 24 to 25

    Fedora 25 was released a few days ago.

    I've upgraded one of my machines. The others are soon to follow. Fedora 25 switches from X11 to Wayland as a default. For my laptop I had to switch last release because my laptop's touchpad was nowhere to be found in X. For this release I am looking forward to not getting to play games on my main desktop. I am sure to blog about any problems I happen upon.

    If you're running Fedora 24 you can easily upgrade to Fedora 25 running the following console commands. But before that, make sure your system is fully upgraded and rebooted, especially if you installed some kernel updates.

    sudo dnf install dnf-plugin-system-upgrade
    sudo dnf system-upgrade download --releasever=25 --allowerasing

    The --allowerasing argument allows some packages to be deleted during the process. I had some dangling haskell packages, that needed to be deleted. No problem there.

    Once all the downloads are done, type sudo dnf system-upgrade reboot to reboot your system starting the actual upgrading process.

    And yeah, I broke my work setup that used proprietary NVidia drivers to get a second monitor running.

  3. Fedora 24 issues

    So I've been running Fedora 24 on my laptop for a bit and its not as nice as I would have hoped.

    First of all, Fedora was no longer under the impression that my device had a touchpad, which it most certainly does. This problem was fixed by moving from the GNOME X-session to the Wayland session. With Wayland, Chrome isn't maximized when it starts even though it thinks it is, but thats just a minor issue. the main problem is that with Wayland, my system no longer recognizes any but the native resolution of my display panel. This is, in itself, not a problem. But any attached projector is also only recognized with its native resolution, leading to the inability to clone the display across both the panel and the projector since they no longer have any resolution in common.

    So now I can decide between using my touchpad or a projector.

  4. Using the C.H.I.P. flasher for Chrome on Fedora

    C.H.I.P. Flasher

    C.H.I.P. Flasher

    Flashing the CHIP from Fedora using the Chrome Flashing plugin is only a little bit different from using Ubuntu. We still have to add the user to the dialout group, to allow accessing the device from the user's context (without root).

    sudo usermod -a -G dialout $(logname)

    If you're doing arduino-programming, you might already be member of the dialout-group. This can be checked with the groups command. If dialout is mentioned, then you can skip this step and also the re-logging.

    Then we need to create a file /etc/udev/rules.d/70-allwinner.rules with the following content:

    SUBSYSTEM=="usb", ATTRS{idVendor}=="1f3a", ATTRS{idProduct}=="efe8", TAG+="uaccess", SYMLINK+="usb-chip"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="1010", TAG+="uaccess", SYMLINK+="usb-chip-fastboot"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="1f3a", ATTRS{idProduct}=="1010", TAG+="uaccess", SYMLINK+="usb-chip-fastboot"
    SUBSYSTEM=="usb", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", TAG+="uaccess", SYMLINK+="usb-serial-adapter"

    This links the CHIP to a location that the Flasher can identify. If you're doing other Allwinner-Flashing (I think the OrangePi does have a similar chip), you might run into problems here. But if you allready do, you probably know whether you're affected or not.

    Finally, one needs to reload the udev-rules with sudo udevadm control --reload-rules and logout and login again (or reboot), if the dialout group was added this session. And after that, the flasher should work fine.

Page 1 / 2 »



Theme based on notmyidea