Sunday, December 13, 2015

Low cost airlines online pricing hacks

Low cost airlines are the masters of dynamic pricing, bundling and pricing psychology.

Every customer who makes an online booking presents them with some new data to plug into their dynamic pricing algorithm. They also analyse the best way to present the various upgrades available to purchase before the final checkout, to maximise the customer's spend.

I've just taken a look at budget carrier JetStar's booking experience and its use of various pricing techniques and psychology.

After you've searched and selected your flights you'll be presented with a choice. Look at how unattractive they make the "Starter fare" default option ...


The "Plus bundle" at $106 is the one JetStar wants you to pick. The "Max bundle" at $753.49 is just there as an anchor price, to give you the impression that the middle one is good value. The "Starter fare" is the one they want you to avoid. They do this through the selective use of negative and positive language and the colours of grey, green and blue.

The Starter fare

Comfortable leather seat
This is patronising ... is there so little going for this bundle option that they have to mention that you actually get a seat, as opposed to standing in the aisle?

7kg carry on baggage
Strict size and weight limits apply

Negative tone. 7kg is not enough for most people's needs.

Checked baggage not included
Repeated, negative tone.

Starter fares are non-refundable
Negative tone.

... compare this to the most popular option, the option JetStar wants you to choose ...

The Plus bundle

No change fees
Positive.

2,225 Qantas points
Free money. Only $30 credit off your next fare, but its better than nothing.

Free standard seat selection
The power of free.

Meal
More included stuff.

20kg checked baggage
Notice they don't mention that a strict size and weight limit also applies to the 20kg baggage.


People are scared of change fees

Most people when seeing the starter fare option will get the impression that if they need to change their flight for any reason, perhaps due to a flight delay, they are in trouble. In fact, JetStar covers you for flight delays and will make the necessary arrangements and additional bookings free of charge. But they only mention this in the fine print.

Most people want checked baggage

You also get the impression that you have to choose the plus bundle or max bundle if you want checked baggage. Actually, you can choose the starter fare, and then later on in the process you can optionally pay for only the specific amount of checked baggage that you need, at a rate of $46 for 15kg, $50 for 20kg and $62 for 25kg. Most customers likely don't know that these cheaper options are available, and will just choose the plus bundle, paying $106, when all they needed was checked baggage. You can select the Starter fare, then pay separately for 20kg checked baggage ($50), a meal ($15) and a reserved seat ($6) and the total will be just $71, a saving of $35 on the Plus bundle.

Noone wants to be randomly assigned a seat

When it comes to selecting a seat, its a bit disingenuous for JetStar to claim this ...

"You have not selected a seat. If you do not wish to pre-select a seat one will be assigned for you randomly from what is still available at check-in."

When you check in at many airports, assuming you get to the airport early and the plane isn't sold out, you'll still be able to select what type of seat you want - the check-in staff are usually more than helpful and should be able to provide your choice of a window or an aisle seat.

If you're a family with children, the airline will try to assign an adult family member to be sitting close to each child in your family, even when you didn't pay to reserve a seat. If you can't be accommodated at the point of check in, you would likely be able to work something out after boarding by speaking to the cabin crew.

Also, remember this inconspicuous bit of writing at the bottom ...

"Jetstar will attempt to accommodate your seat preference, however due to operational considerations cannot guarantee that your seat allocation will be as your selected preference."

So in other words, they ask you to pay for a seat preference, but cannot guarantee it.


Follow @dodgy_coder

Subscribe to posts via RSS

Monday, June 15, 2015

The Default Files Folder Pattern

Software installation best practices

When you've got critical settings files that absolutely should never be overwritten or cleared back to defaults, this pattern has always worked well for me. It can apply to both Windows, Linux and Mac based software.

The installation method can either be a simple file copy utility/archive or something more complex like a Windows installer.

An example target structure might look something like this:

/MyApplication
    /bin           => Application binaries.
    /defaults      => A default version of all
settings files.
    /docs          => Documents or manuals.
    /settings      => Critical settings files.

             
The settings folder contains the critical settings files and is not part of the installer. The installer includes only the bin, defaults and docs folders. So installing the software only overwrites bin, defaults and docs, but never the settings. This applies equally to Windows installer packages - for this case, just don't include the settings folder in the Windows installer package. The defaults folder contains the default version of all of the the files expected in the settings folder.

Whenever the software accesses a particular file in settings the following lazy initialisation logic is used ...

- Does the settings folder exist?
    - Yes: Continue
    - No:  Create the folder and continue
   
- Does the file exist?
    - Yes: Open it
    - No:  Copy the file from the
defaults folder into the
           settings folder, then open it

By following the above logic, you ensure that an existing critical settings file is never overwritten.

From reading the latest report on the deadly Airbus A400M crash, its claimed that the cause was that their software installation procedure did the equivalent of overwriting a settings file or clearing it back to defaults. In this case, the settings file contained calibration parameters that were critical to the operation of 3 out of the 4 propeller engines.

Follow @dodgy_coder

Subscribe to posts via RSS

Saturday, May 2, 2015

Taking control of a 36 year old NASA spacecraft using GNU radio

In 2014, Dennis Wingo and Keith Cowing formed the ISEE-3 Reboot Project, a crowdfunded effort to attempt to gain control of the decommissioned spacecraft for the benefit of citizen science. The team raised almost $160,000 in funding and assembled top space experts for the cause. In May, 2014, they began communicating with the spacecraft in advance of its August 10th 2014 lunar fly by.

Here's an excerpt of a brilliant podcast interview between software defined radio (SDR) specialist, Balint Seeber, and Infosec journalist, Patrick Gray, as recorded on April 24, 2015. Its the best anecdote about technology and hacking I've heard recently.

Below transcript starts at the [47m:43s] mark of the Risky Business podcast #363
.

Balint: It was also to set a precedent for citizen scientists from the public to essentially take over missions that ... all the missions that NASA may not want to spend its resources, its precious, you know resources and budget on. So this was supposed to be a good first example of how they could do that hand-off to a public group, and there were initial negotiations there and a Space Act agreement was signed so it was all above board and legitimate.

We realised the reason they got in touch with Ettus Research and then with me and my former colleague, John Malsbury, who funnily enough now works at SpaceX, so he's still in the space game, but he and I met with the guys and they basically told us the reason why we need your expertise is because NASA has thrown out all of the old equipment they used to speak to the space probe. So they put the space probe in this graveyard orbit, because the mission had finished and they ran out of funding, but there was no way for the NASA deep space network to actually send it commands to wake it back up again.

And so, having done their techno-archeology, as they like to put it, retrieving all these old NASA documents, we could see the various protocols that would be necessary to re-implement, using software defined radio, in this case GNU radio, to achieve this, you know, recreate the modems to talk to it. And so we did that and we were fortunate enough to be able to go to the Arecibo radio telescope in Puerto Rico, hook our software defined radios up to their big, big telescope, and then send these commands out to the probe, which at the time I think was 15.5 million kilometres away, travelling towards the earth at about four kilometres a second ...

Patrick: That's a long distance call...

Balint: Its a very long distance, and I call it "not your average radio link budget". But we managed after some initial attempts to have some success there and send the commands out to turn the telemetry on. We could then assess the health of the space probe and ...

Patrick: And you did your happy dance of course when the response came back?

Balint: That's true, yeah, we had our unmodulated carrier suddenly become modulated telemetry and it was the first real major milestone of the project. All that preparation that we'd done, all the interpretation of the documents and taking into account the various permutations of parameters and ...

Patrick: And the plan of course was to fire the thrusters in a way to get it into a stable orbit and they you guys could use the various sensors and things on it to quote "Do Science", uh, but it didn't quite work out did it?

Balint: No, unfortunately the grand idealist game was to reactivate all of the operational science instruments on board and actually bring it back and do proper, public science with it, and, you know, have it available for STEM and so on, but unfortunately when we tried to fire the thrusters, in all the different configurations, because there were lots of redundancies in the propulsion system, we never observed any impulse being registered on the accelerometer and the accelerometers data was being transmitted back on the telemetry and it would always sort of flat line. And this was a big disappointment for us, no matter what we tried we just couldn't get the thing to move, and one of the running theories is that the (fuel) tanks were actually pressurised with nitrogen so that it would force the fuel out, back into the rest of the propulsion system, as in the valves and the thrusters, and you could imagine that over the three decades there might have been a very, very slow leak and that nitrogen pressure, it might have just leaked out over time and unfortunately now its left us with an inoperable propulsion system.

Patrick: What, no backup fuel pump? (sarcastic)

Balint: Can you believe it?

Patrick: Bloody American engineering.

Balint: What were those NASA boffins thinking? (laughing)

Patrick: But you were able to actually fire up the sensors and do some science with it. What was the total budget of this project, that was crowdfunded in the end?

Balint: They used Rockethub and I think it was on the order of $150,000, so it was quite a nice little collection there, and yeah, some of the science instruments were reactivated and we actually for a short period got some good science data out of it, which was great, and it was quite funny, when I was at DEFCON last time, I got the call that one of the science instruments needed to be rebooted and I had been waiting for quite a long time in line to get a good seat and there were a number of back to back presentations that I was ...

Patrick: Excuse me I'll be back I've just got to go give the three finger salute to a satellite

Balint: Well that's the thing though, I didn't want to leave and so, unfortunately I didn't have any cell reception so I couldn't tether to my phone, you don't get on the WiFi at DEFCON obviously because then you open yourself up to being hacked. So there's a guy next to me that I started to talk to and we're talking about software defined radio and I sort of sized him up, he was from Norway and he seemed like a good bloke and I asked whether I could tether to his phone. He said yes because he had a prepaid account with some Internet credit on there. And so I ended up tethering to his phone, SSH-ing from the third row of DEFCON into the laptop at Arecibo to send commands to the space probe that was about to fly past the moon, to reboot the science instrument on board, and then I could continue watching the presentation, so it was quite fun.

Patrick: Its a pretty amazing time isn't it...

Balint: Well it just goes to show you how interconnected the entire world is, I mean you've got the WiFi from my laptop to the phone, LTE from the phone to the cellular network, and then the data connection obviously across that and then down to Arecibo and then our custom link to the space probe. So it was a good testament both to SDR and commercially deployed wireless standards.


Futher information ...
Communicating with a space probe using Software Defined Radio

... a video of a presentation Balint gave to the Manly Warringah Radio Society ...


Follow @dodgy_coder

Subscribe to posts via RSS

Saturday, February 28, 2015

Setting up a Bonjour (Zeroconf) service name for your Raspberry Pi and accessing it from an Android App

I have written an Android app that communicates to my Raspberry Pi over SSH (using JSch) but the issue is that in the App the IP address of my Raspberry Pi has been hardcoded at 192.168.1.109 - ideally it would be good to be able to give it a local name, something like garagedoor.local - something that won't change when the DHCP assigns a different IP address.

It turns out that the way to do this isn't difficult on the Raspberry Pi and most of work is in changes to the Android App needed to make it happen. I've numbered the steps 1-4.

1. Configuration of your Raspberry Pi.

# Get superuser privileges
sudo su

# Change the host name of your Raspberry Pi from "raspberrypi" to "garagedoor"
# Reference: http://www.howtogeek.com/167195/how-to-change-your-raspberry-pi-or-other-linux-devices-hostname/

sudo nano /etc/hosts            # <== Replace raspberrypi with garagedoor
sudo nano /etc/hostname         # <== Replace raspberrypi with garagedoor

sudo /etc/init.d/hostname.sh    # Commit the changes.
sudo reboot                     # Reboot

# Install the mDNS implementation - avahi
# Reference: http://www.howtogeek.com/167190/how-and-why-to-assign-the-.local-domain-to-your-raspberry-pi/
# Get superuser privileges
sudo su

# Update the package sources
apt-get update

# Ugrade the packages
apt-get upgrade

# Install the mDNS implementation - avahi
sudo apt-get install avahi-daemon



That's the end of the changes needed on your Raspberry Pi.

2. Test on either Windows, Linux or Mac OSX that the Raspberry Pi is visible on the network with its new name of "garagedoor.local".

On Windows, you will need to have Bonjour Networking Services installed, which comes bundled with iTunes.
Run a cmd.exe prompt and type the command ping garagedoor.local -- you should get a response from your Raspberry Pi.

On Mac OSX, Bonjour Networking Services are installed by default.
In a bash terminal window, type the command ping garagedoor.local -- you should get a response from your Raspberry Pi.

On Linux, first ensure you have installed the avahi-daemon package.
In a bash terminal window, type the command ping garagedoor.local -- you should get a response from your Raspberry Pi.

3. Using NSD (Network Service Discovery) on Android to resolve the Raspberry Pi's service name.

Browsers and terminal programs on Android won't be able to resolve the garagedoor.local since to do this requires use of either the official Network Service Discovery library (supported by API Level 16 up) or the open source Java Zeroconf library named jMDNS.

In my case, I am using a custom app I wrote to communicate to the Raspberry Pi, so I have decided just to use the Network Service Discovery library.

4. Source code changes needed in the Android App to support NSD (Network Service Discovery)

Notes:
 (1) Below is just how I decided to implement it, you may want to separate the NSD related code out of the Activity into its own class, but for me that wasn't a problem.
 (2) I probably need to do something related to NSD in the Application lifecycle events of onPause(), onResume(), onDestroy() and onTeardown(). I haven't done that here yet.


4.A. Add some members to the Activity

I added this to my MainActivity but my app is small and so that's all I needed to do.

// Network Service Discovery related members
// This allows the app to discover the garagedoor.local
// "service" on the local network.
// Reference: http://developer.android.com/training/connect-devices-wirelessly/nsd.html
private NsdManager mNsdManager;
private NsdManager.DiscoveryListener mDiscoveryListener;
private NsdManager.ResolveListener mResolveListener;
private NsdServiceInfo mServiceInfo;
public String mRPiAddress;

// The NSD service type that the RPi exposes.
private static final String SERVICE_TYPE = "_workstation._tcp.";

   
4.B. Add some init code to the bottom of the Activity's onCreate() method.

mRPiAddress = "";
mNsdManager = (NsdManager)(getApplicationContext().getSystemService(Context.NSD_SERVICE));

initializeResolveListener();
initializeDiscoveryListener();
mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);

   
4.C. Add the following two new methods to your Activity.

 private void initializeDiscoveryListener() {

     // Instantiate a new DiscoveryListener
     mDiscoveryListener = new NsdManager.DiscoveryListener() {

         //  Called as soon as service discovery begins.
         @Override
         public void onDiscoveryStarted(String regType) {
         }

         @Override
         public void onServiceFound(NsdServiceInfo service) {
             // A service was found!  Do something with it.
             String name = service.getServiceName();
             String type = service.getServiceType();
             Log.d("NSD", "Service Name=" + name);
             Log.d("NSD", "Service Type=" + type);
             if (type.equals(SERVICE_TYPE) && name.contains("garagedoor")) {
                 Log.d("NSD", "Service Found @ '" + name + "'");
                 mNsdManager.resolveService(service, mResolveListener);
             }
         }

         @Override
         public void onServiceLost(NsdServiceInfo service) {
             // When the network service is no longer available.
             // Internal bookkeeping code goes here.
         }

         @Override
         public void onDiscoveryStopped(String serviceType) {
         }

         @Override
         public void onStartDiscoveryFailed(String serviceType, int errorCode) {
             mNsdManager.stopServiceDiscovery(this);
         }

         @Override
         public void onStopDiscoveryFailed(String serviceType, int errorCode) {
             mNsdManager.stopServiceDiscovery(this);
         }
     };
 }

 private void initializeResolveListener() {
     mResolveListener = new NsdManager.ResolveListener() {

         @Override
         public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
             // Called when the resolve fails.  Use the error code to debug.
             Log.e("NSD", "Resolve failed" + errorCode);
         }

         @Override
         public void onServiceResolved(NsdServiceInfo serviceInfo) {
             mServiceInfo = serviceInfo;

             // Port is being returned as 9. Not needed.
             //int port = mServiceInfo.getPort();

             InetAddress host = mServiceInfo.getHost();
             String address = host.getHostAddress();
             Log.d("NSD", "Resolved address = " + address);
             mRPiAddress = address;
         }
     };
 }


4.D. Make use of the mRPiAddress member where previously you used a hardcoded IP address.

Check that its not empty before using it. If its empty, it means the RPi's name couldn't be resolved.


Follow @dodgy_coder

Subscribe to posts via RSS




Saturday, February 21, 2015

Anders Hejlsberg: C# stands for C++++

Just came across this today. Previously had heard the association with the musical sharp symbol (#) to mean a pitch higher in tone, but this was the first time I'd heard that the # symbol can also be seen as a matrix of four small + symbols, hence C# stands for C++++, i.e. an increment to C++.

Source: http://www.computerworld.com.au/article/261958/a-z_programming_languages_c_/?pp=2

Follow @dodgy_coder

Subscribe to posts via RSS