Heat Maps!

heatmap-720x340

Borne out of the need to get some kind of visual understanding of how GeeOhTileServer is performing/being used, I decided to start implementing heat map images for the various zoom levels.

Aside from indicating any potential issues (because I will be plotting errors/failures also), this will be a great help in identifying general locations of users and getting a literal picture of the overall use of MakingTracksGPS.

It will look damn pretty too ūüôā

A few related tasks that I’ll be working on tonight are:

  • Auto-expanding images
    • Re-sizing and re-applying existing data when new data is outside bounds
  • Rendering a grid or some sort of scale indicator
  • Working on JavaScript to dynamically display this in admin page(s)
  • Store update events for the heat maps, and apply them periodically as a batch, in synchronized code block

Watch this space!

 

TRP

Got You, You Little Bastard!

homer_choking_bart

Oh my God, finally. I’ve been chasing after a bug – on and off – for months now, and at last I¬†cracked it today.

In the new MakingTracksGPS, there was this minor but very irritating bug where the location marker would periodically jump back a little bit during a pinch/zoom event. I tried so many fixes for this, absolutely none of which made a blind bit of difference. Until today.

I noticed that the rendering jump occurs quite reliably if you zoom in/out, then just keep your fingers still on the screen. So it wasn’t due to the actual zoom event, but rather something that wasn’t being reset¬†until you let go.

Upon examining the ACTION_UP code block, I noticed a variable tempDisableInterpolation being set to false, so I followed its behaviour and Рlo and behold Рwhen this remains true, it results in incorrect calls to centre display on (effectively an incorrect) location.

I did a bit of refactoring, altered (ie. improved) the general behaviour of interpolated zoom, and now there is zero trace of this tacky, jumpy display error.

Result!

Now I’m down to four things on my “Barriers To Release” list:

  • UniqueID DB table(s) and handling/monitoring the recording of usage stats
  • Placenames rendering
  • Pre-population of map tiles on GeeOhTileServer
    • Need to be conscious of storage limitations
  • ProGuard builds

And that will be it, I’ll be shoving the v2.0 Beta out the door ASAP.

 

TRP

Toilet Seat Inequality SOLVED!

jackie_chan

I’m not sure about the rest of the World, but in the UK it seems quite prevalent that women will complain if they have to put the toilet seat down before use, and I’ve had many an argument about this with previous girlfriends and now my wife.

Arguments like “it’s just easier for everyone” and “it’s not fair that I should¬†always¬†have to put the seat down” are often used, but instinctively they’ve always seemed wrong. I’ve always felt (and argued) that a fairer system is to just put the seat to whichever position you require, and then leave it as it is, because I was sure this meant generally less fannying about with the seat for all concerned.

And now, through the medium of Java code, I have proven it. Behold:

public class FairnessTest {
     private boolean okayToRun = true;
     private Seat seat;
     private final String SEAT_UP = "UP";
     private final String SEAT_DOWN = "DOWN";
     private final String NEEDS_ONE = "#1";
     private final String NEEDS_TWO = "#2";
     private final Object doorLock = new Object();
     // NOTE: Toggle this boolean to change whether or not seat has to be reset to "DOWN" position, after use
     private boolean seatResetRequired = true;
     
     private int visitTotal = 0;
     private int toggleTotal = 0;
     private int visitTotalMale = 0;
     private int toggleTotalMale = 0;
     private int visitTotalFemale = 0;
     private int toggleTotalFemale = 0;
     
     public static void main(String[] args){
         new FairnessTest();
     }
     
     public FairnessTest(){
         // create the Seat
         seat = new Seat();
         
         // create 2 men and 2 women, and start their behaviour
         new Man("Jeff").start();
         new Man("Bill").start();
         new Woman("Betty").start();
         new Woman("Agnes").start();
         
         // wait 60 seconds on the main thread, then terminate all behaviour
         try {
             Thread.sleep(60000);
         }
         catch (Exception e){}
         okayToRun = false;
         
         // readout results
         System.out.println("");
         System.out.println("RESULTS");
         System.out.println("=======");
         System.out.println("Total Visits: " + visitTotal);
         System.out.println("Total Toggles: " + toggleTotal);
         System.out.println("Toggle percentage: " + (int)(((double)toggleTotal / (double)visitTotal) * 100) + "%");
         System.out.println("Male Total Visits: " + visitTotalMale);
         System.out.println("Male Total Toggles: " + toggleTotalMale);
         System.out.println("Male Toggle percentage: " + (int)(((double)toggleTotalMale / (double)visitTotalMale) * 100) + "%");
         System.out.println("Female Total Visits: " + visitTotalFemale);
         System.out.println("Female Total Toggles: " + toggleTotalFemale);
         System.out.println("Female Toggle percentage: " + (int)(((double)toggleTotalFemale / (double)visitTotalFemale) * 100) + "%");
     }
     
     
     /**
      * INTERNAL CLASSES.
      */

    class Man extends Thread {
         private String name;
         private String needs;
         
         public Man(String name){
             this.name = name;
         }
         
         public String toString(){
             return name;
         }
         
         public void run(){
             while (okayToRun){
                 try {
                     sleep((int)(Math.random() * 10000));
                 }
                 catch (Exception e){}
                 
                 if (okayToRun){
                     synchronized (doorLock) {
                         visitTotal++;
                         visitTotalMale++;
                         
                         System.out.println("");
                         System.out.println(this.toString() + " enters");
                         
                         String currentSeatStatus = seat.getStatus();
                         String requiredSeatStatus = getRequiredSeatStatus();
                         
                         if (!requiredSeatStatus.equals(currentSeatStatus)){
                             toggleTotal++;
                             toggleTotalMale++;
                             seat.toggleStatus();
                             System.out.println(" **" + this.toString() + (requiredSeatStatus.equals(SEAT_UP) ? " raises seat**" : " lowers seat**"));
                         }
                         
                         System.out.println("    " + this.toString() + " uses for " + needs);
                         
                         if (seatResetRequired && seat.getStatus().equals(SEAT_UP)){
                             System.out.println(" **" + this.toString() + " resets seat**");
                             toggleTotal++;
                             toggleTotalMale++;
                             seat.toggleStatus();
                         }
                         
                         System.out.println(this.toString() + " leaves");
                     }
                 }
             }
         }
         
         private String getRequiredSeatStatus(){
             // assuming ratio of 4:1 for 1's and 2's
             if (Math.random() <= 0.2){
                 needs = NEEDS_TWO;
                 return SEAT_DOWN;
             }
             needs = NEEDS_ONE;
             return SEAT_UP;
         }
     }

    class Woman extends Thread {
         private String name;
         private String needs;
         
         public Woman(String name){
             this.name = name;
         }
         
         public String toString(){
             return name;
         }
         
         public void run(){
             while (okayToRun){
                 try {
                     sleep((int)(Math.random() * 10000));
                 }
                 catch (Exception e){}
                 
                 if (okayToRun){
                     synchronized (doorLock) {
                         visitTotal++;
                         visitTotalFemale++;
                         
                         System.out.println("");
                         System.out.println(this.toString() + " enters");
                         
                         String currentSeatStatus = seat.getStatus();
                         String requiredSeatStatus = getRequiredSeatStatus();
                         
                         if (!requiredSeatStatus.equals(currentSeatStatus)){
                             toggleTotal++;
                             toggleTotalFemale++;
                             seat.toggleStatus();
                             System.out.println(" **" + this.toString() + (requiredSeatStatus.equals(SEAT_UP) ? " raises seat**" : " lowers seat**"));
                         }
                         
                         System.out.println("    " + this.toString() + " uses for " + needs);
                         
                         if (seatResetRequired && seat.getStatus().equals(SEAT_UP)){
                             System.out.println(" **" + this.toString() + " resets seat**");
                             toggleTotal++;
                             toggleTotalFemale++;
                             seat.toggleStatus();
                         }
                         
                         System.out.println(this.toString() + " leaves");
                     }
                 }
             }
         }
         
         private String getRequiredSeatStatus(){
             // assuming ratio of 4:1 for 1's and 2's
             if (Math.random() <= 0.2){
                 needs = NEEDS_TWO;
             }
             else {
                 needs = NEEDS_ONE;
             }
             return SEAT_DOWN;
         }
     }
     
     class Seat {
         public String seatStatus = SEAT_DOWN;
         
         public String getStatus(){
             return seatStatus;
         }
         
         public void toggleStatus(){
             seatStatus = seatStatus.equals(SEAT_DOWN) ? SEAT_UP : SEAT_DOWN;
         }
     }
 }

The code looks a bit truncated on here, but just copy and paste it where you need to get it running.

After 6 runs, 3 where the seat is left “as is” and 3 where the seat is always reset to down, the results were as follows:

WITHOUT RESET
-------------

RESULTS
=======
Total Visits: 59
Total Toggles: 27
Toggle percentage: 45%
Male Total Visits: 32
Male Total Toggles: 17
Male Toggle percentage: 53%
Female Total Visits: 27
Female Total Toggles: 10
Female Toggle percentage: 37%

RESULTS
=======
Total Visits: 44
Total Toggles: 25
Toggle percentage: 56%
Male Total Visits: 21
Male Total Toggles: 13
Male Toggle percentage: 61%
Female Total Visits: 23
Female Total Toggles: 12
Female Toggle percentage: 52%

RESULTS
=======
Total Visits: 46
Total Toggles: 26
Toggle percentage: 56%
Male Total Visits: 20
Male Total Toggles: 15
Male Toggle percentage: 75%
Female Total Visits: 26
Female Total Toggles: 11
Female Toggle percentage: 42%


WITH RESET
----------

RESULTS
=======
Total Visits: 41
Total Toggles: 34
Toggle percentage: 82%
Male Total Visits: 21
Male Total Toggles: 34
Male Toggle percentage: 161%
Female Total Visits: 20
Female Total Toggles: 0
Female Toggle percentage: 0%

RESULTS
=======
Total Visits: 51
Total Toggles: 46
Toggle percentage: 90%
Male Total Visits: 28
Male Total Toggles: 46
Male Toggle percentage: 164%
Female Total Visits: 23
Female Total Toggles: 0
Female Toggle percentage: 0%

RESULTS
=======
Total Visits: 51
Total Toggles: 32
Toggle percentage: 62%
Male Total Visits: 27
Male Total Toggles: 32
Male Toggle percentage: 118%
Female Total Visits: 24
Female Total Toggles: 0
Female Toggle percentage: 0%

The results speak for themselves. Even with the “no reset” system, the women still don’t have to alter the seat as much as the blokes. It’s win-win for them.

So¬†gentlemen, leave the seat up when you’ve finished, it’s the right¬†thing to do.

 

TRP