The Me Meme

Me right now!
Me right now!

Take a picture of yourself right now.
Don’t change your clothes, don’t fix your hair…just take a picture. (should be super-easy with Photobooth)
Post that picture with NO editing.
Post these instructions with your picture.

Via Raganwald

Update from the United States

Well I have not posted for a while, and that has mostly been because I have been getting ready for, traveling, or just being in the States.

So far I have had a grill (NZ BBQ) in Livermore (San Francisco), CA

Visited a mine site (but not gone out into the actual Mine) in Gillette, WY

Visited Caterpillar’s massive proving grounds in Peoria, IL

Gotten bored in Las Vegas, NV (where I currently am)

After a couple of Hotels with free Wifi/Internet, free breakfast and free local calls, Las Vegas is to be a huge disappointment of what it deliveries and a huge just pay more at each step.

However, MinExpo 2008 is fantastic, and I’ll take my camera tomorrow and capture many great big machines close-up.

TimeDirection graph

A work college was wanting some trivial code to draw a time based direction plot, and insisted that I do it.

So here is my drawing class:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace LineCurve
{
  public class TimeDirection
  {
    public void Draw(Graphics g, Panel pnl, List<KeyValuePair<int,float>> data, int maxtime)
    {
      using (Brush brush = new SolidBrush(Color.Blue))
      {
        float halfx = pnl.Width / 2.0f;
        float halfy = pnl.Height / 2.0f;
        float scale = Math.Min(halfx, halfy) / (float)maxtime;

        foreach (KeyValuePair<int, float> kvp in data)
        {
          int time = kvp.Key;
          double dir = kvp.Value / 180.0 * Math.PI;

          // subtrack y as 0 is top, and +y is bottom.
          float fx = (float)(halfx + (Math.Sin(dir) * scale * time));
          float fy = (float)(halfy - (Math.Cos(dir) * scale * time));

          g.FillRectangle(brush,fx, fy, 1.0f, 1.0f);
        }
      }
    }
  }
}

And given the input:

List<KeyValuePair<int,float>> data = new List<KeyValuePair<int,float>>();
for (int i = 0; i < 40; i++)
{
  data.Add(new KeyValuePair<int, float>(i, i * 9.0f));
}

Looks like this:

time/direction based graph
time/direction based graph

This code is released under the MIT license, except it may not be used for web-based weather applications.

Learning to use foldl and map

I have been working on a small line drawing project, and part of that project is indexing nested lists based on sets of indices.

Firstly I wrote a function to return the recursive nth item.  So for this data [[[1,2],[3,4]],[[5,6],[7,8]]] and the input [1,2,1] the value 3 is returned.  Here’s my original function:

point(Cube,[First|Rest]) ->
  point(lists:nth(First,Cube),Rest);
point(Cube,[]) ->
  Cube.

I then had a couple of functions to return point lists for each list of points look-ups.  The first line was for connected points, and the second lines to draw separate lines.  So using the same data above, and the input [[1,2,1],[2,2,2],[1,1,1]] to line would generate [3,8,1], and lists of that input to lines creates lists of results.  Brilliant I know, here’s my code:

lines(Cube,Lines) ->
  lines(Cube,lists:reverse(Lines),[]).

lines(_Cube,[], Output) ->
  Output;
lines(Cube,[First|Rest], Output) ->
  lines(Cube,Rest,[line(Cube,First)|Output]).

line(Cube,Points) ->
  line(Cube,lists:reverse(Points),[]).
line(Cube,[First|Rest],Output) ->
  line(Cube,Rest,[point(Cube,First)|Output]);

line(_Cube,[],Output) ->
  Output.

I used a wrapper function to reverse the input, to solve the list construction order.  I was quite proud of my groking tail recursion.  But couldn’t help notice line and lines are the same, but not the same.  While reading how to do the output formatting, I came across some good examples on using foldl and map.  Surprise, the examples where like my functions, so I rewrote them like this (renaming point to nth_nth):

lines(Cube,Lines) ->
  lists:map(fun(Line) -> line(Cube, Line) end, Lines).

line(Cube,Points) ->
  lists:map(fun(Point) -> nth_nth(Cube, Point) end, Points).

nth_nth(Vals,Nths) ->
  lists:foldl(fun(Nth,List) -> lists:nth(Nth,List) end, Vals, Nths).

Much better, but I started to have a nagging feeling about using anonymous functions to just call a single function.  I then found the way to refer to other functions by name, but this does not work for the map as I am binding an extra variable, but for foldl it does work as it’s arity is 2, thus nth_nth can be written as:

nth_nth(Vals,Nths) ->
  lists:foldl({list,nth}, Vals, Nths).

I thought the use of the fold function to return nested look-up results was clever. The new functions have less total lines, but each line is much denser, so may appear harder to read, but I am using standard functions so the cost to comprehend should be lower.

Evils of typedefs and legacy code

Our legacy C++ codebase once was a C codebase.  Way back then, there was no standard boolean type.  So in the wisdom of the day a type was declared

typedef int tBool;

The major problem with tBool’s is that over time enums, #define or magic constants get assigned to them, or they can be compared to said enums, #defines or magic constants, as they are all int’s.

Which works, but years later *somebody* came along and replaced the tBool for bool, and we started getting issues.

Now as in a lot of large codebases there tends to be a large amount of ignored warnings, and not enough daylight hours to remove them all.

So given that, and that your using Visual Studio 2005, here are the ones you should find and remove.

#define NON_BOOL_DEFINE 42
bool boolValue;

boolValue = NON_BOOL_DEFINE;

gives:

Warning C4305: '=' : truncation from 'int' to 'bool'

also

if( boolValue == NON_BOOL_DEFINE )

gives:

Warning C4806: '==' : unsafe operation: no value of type 'bool' promoted to type 'int' can equal the given constant

Another hint your boolean types are being used wrong is this warning

Warning C4800: 'const int' : forcing value to bool 'true' or 'false' (performance warning)

0×1F Today

Today is my 0x1F birthday.

Pre-writing this, therefore I still don’t know what I getting.  I’m taking the day off from work, so it’s looking good already.

The Olympics

Well 2008 Olympics, and I have enjoyed it quite a bit.  I really enjoyed the opening ceremony, and it was a great chance to use the PVR to record the whole thing.

It will be good to not feel compelled to have the TV on for a while.  When so much top level competition is happening I feel that I need to enjoy it all…

Things I will not miss, and think should be scraped are:

Walking race - really how is this a sport, it’s so contrived, ‘lets run, but without running‘. I mean you walk when you don’t want to run, or you run when your late and have a need to get there faster.  So running races are about going as fast as you can, yet the walk (I don’t want to go fast) race, is about going as fast as you can without going fast, how can that be a race.

Womans beach volleyball - lets get a great team sport, and empty the court of most of the players so that points are easy to get.  Oh and now lets skimp the togs down so people watch.  Um, if the people are not watching it’s because it’s boring.  So tarting it up means only oglers will watch - is that what the Olympics is about, perving?

My other major gripe I have is with sports that could be defined as a ‘game’.  Football, Baseball, Softball and Tennis are not really higher, longer, faster are they.  Ok, there are some team games I do like, but would be willing to loose, Volleyball, Table Tenis.  I just don’t see ‘games’ as personal excellence.

My last gripe, is that TV One had four TV streams available on-line, but our Internet plan charges for traffic because ‘international traffic is expensive‘ yet local traffic also gets billed at these rates, because ISPs can. Nice one ISPs.

Slow sub-select maybe LAG or LEAD might help

One of the queries in our application is used to edit event entries.  Event entries have a start time and an end time, but when they are processed from the data files, they can be entered with just a start time (ie when the event started), but in cases of problems (crashes) these entries will not have matching entries with end time.

So in our editor, we are wanting to know the upper limit of when the event could have ended, which is the next start time.

ROWID    TIME_START   TIME_END  OTHER_FIELDS
1        2008-1-1     null      data
2        2008-1-2     2008-1-3  more data

So for row 1 we want 2008-1-2 as the suggested end time.

Originally we had a query that looked like this:

SELECT other_fields,
  TIME_START,
  TIME_END,
  NVL((
      SELECT MIN(TIME_START)
      FROM some_view
      WHERE MACHINE_ID = T1.MACHINE_ID
        AND TIME_START > T1.TIME_START
    ), TIME_START + 1/24) "NEXT_TIME_START"
  FROM some_view T1
  WHERE MACHINE_ID = machine_id
    AND NVL(TIME_END,
            NVL((
                  SELECT MIN(TIME_START)
                  FROM some_view WHERE MACHINE_ID = T1.MACHINE_ID
                  AND TIME_START > T1.TIME_START),
                TIME_START + 1/24)) > start_time_range
    AND TIME_START < end_time_range ORDER BY TIME_START

So this is a little trickier than described above as it deals with the edge case of when there is no next entry.  In that case the current start time plus 1 hour is used.

This performs fine with small data sets, but when we had over a million rows in that view, the selection of one days data (~2700 rows) took 551 seconds (>9 minutes), and this was one of many large views, so the overall effect was a >30 minute wait.

I rewrote the query with the use of LEAD, and the performance went to 4 seconds (with data retrieval) or 0.6 seconds for a count(*) operation.  Here’s that query now using LEAD.

SELECT *
FROM(SELECT other_fields,
       TIME_START,
       TIME_END,
       NVL( LEAD(TIME_START) OVER (PARTITION BY machine_id ORDER BY time_start),
            TIME_START + 1/24) AS "NEXT_TIME_START",
       FROM some_view T1
       WHERE MACHINE_ID = machine_id )
WHERE NEXT_TIME_START > start_time_range
  AND TIME_START < end_time_range
ORDER BY TIME_START

Now that I review the code I notice I also rearranged the code to not repeat the next_time_start calculation, so I am now not sure all the performance improvements can be attributed to LEAD, but I’ll take that ~138 times improvement either way.