Ramblings of a
Semi-Retired Programmer

12/10/2011 - D Stuff.

Having got back into D with COMPO, I thought I would dust off a couple of things I had done a couple of years ago and see if I could get them up to the current D version and maybe included in the D standard library - Phobos.

I wrote a proposal of sorts on the D newsgroup (news.digitalmars.com), and it kind of got accepted, so now, unless I foul up, I am the point man for this development, which could be quite an epic effort.

My first attempt was mysqlD - an interface to the MySQL database. You can see the documentation here at BritsEyeView, and get the code at github.

Unfortunately, this won't fly for Phobos, since I had to derive a D interface file from mysql.h, which is GPL, but it's available for use by D programmers who can live with the GPL license.

So I had to start over, and I then made a similar interface using the published wire-level MySQL client/server protocol, which is unencumbered license-wise. That is also viewable here, and available on github. Both of these are roughly at the level where you can write:


   auto con = new Connection("host=localhost;user=user;pwd=password;db=mysqld");
   scope(exit) con.close();

   auto c1 = Command(con);
   c1.sql = "insert into basetest (bytecol, intcol, stringcol, datecol) values(?, ?, ?, ?)";
   byte b = 127;
   int n = 1066;
   char[] s = "Whatever".dup;
   auto d = MYSQL_DATE(2011, 11, 11);
   c1.createParams(b, n, s, d);
   ulong ra;
   c1.execPrepared(ra);

My next effort will be ODBCD, with the primary aim of allowing D programmers to connect to Microsoft's SQL Server. This is fraught with licensing issues also, and it may be that I shall have to do two versions of that also, one based on the sql.h and sqlext.h ODBC header files, and one on the TDS wire-level protocol.

There are two other developers in the D community with whom I hope to agree a standard interface approach, and who I hope will then do similar components for PostgreSQL and SQLite.

Then I, or rather I hope we, will have to design and implement an over-bridging architecture so that D programmers can use all of these components in the same way without worrying too much about what kind of database they are using. Currently there is almost zero consensus on the form that this should take. I shall keep prodding at this until the will arises to compromise. This process is I think more like politics than software development.

So as you can see, unless I chicken out, or am thrown out, I have my work cut out for some time.

4/10/2011 - COMPO.

As some readers will already know, I've been working on a graphical design program for Linux called COMPO, and I have created a web page for it here.

I think it is quite cool - but then of course, I would.

It is written in the D programming language using GTK+. If there's any sign of interest, I'll post the source code.

28/8/2011 - Using gtkD - gobject.ObjectG Properties.

The application I'm working on at some point wants to decompose the contents of a TextView TextBuffer to reduce it to a set of fragments that I can then render using the facilities for text rendering provided by Cairo. OK, so I could use Pango, but I don't think that would make any difference to my topic.

So I iterate through the TextBuffer looking for TextTags that I can set up as separate fragments. I can get the font property of a tag quite simply using something like:


Value v = new Value();
v.init(GType.STRING);
textTag.getProperty ("font", v);
string f = v.getString();
But I was stuck for some time on getting the corresponding color property for the tag. The TextTag documentation refers me to a property 'foreground-gdk' of type GdkColor. But there's no immediately obvious way of getting a property with that type.

After reading the documentation - gtkD, and GTK+ - for some time, I attempted to create a boxed type for GdkColor. When I did this I got messages that I eventually interpreted as meaning that the type was already boxed. Once you know this, the problem dissolves. It just boils down to:


v.init(Type.fromName("GdkColor"));
textTag.getProperty ("foreground-gdk", v);
GdkColor* p = cast(GdkColor*) v.getBoxed();
As always, simple when you know how! If you're getting some obscure property, try Type.fromName("propertyType") first. If that fails, than you are asking for a property that is not there, so there's no point in boxing it yourself.
16/8/2011 - Using gtkD - Cairo Transformations Hell.

One of the least intuitive parts of GTK is the way that transformations are applied to a Cairo context. Coming at it from the way most of the operations on a Cairo context work, you'd expect to be able to do something like:


// create some path
context.translate(-dx, -dy);  // move centered object to origin
context.rotate(theta);        // now rotate it about its new origin
context.scale(1.5, 1.5);      // and scale it

context.stroke();             // render the path

context.translate(a+dx, b+dy);    // then move the origin back to the center of the drawing area
                              // maybe shifted a bit
But no. That won't get you anywhere. You have to bear in mind that these transformations are accomplished by applying an affine transformation matrix to the coordinate system of the context. So you first save the context, then screw with its coordinates, and then perform your drawing operation. After that you can do a restore, and carry on as if nothing had happened.

Application of the transformation matrix is, if you like, an atomic operation - just one matrix, just one application of it. First you have to build that matrix, and to do that you multiply together matrices corresponding to the individual transformation operations. As it happens, the order in which these multiplications must take place, is last operation first - as you might say, ass-backwards.

So my bit of pseudo-code should read:


// create some path
context.save();

context.translate(a+dx, b+dy);    // then move it back to the center of the drawing area
context.scale(1.5, 1.5);      // and scale it
context.rotate(theta);        // now rotate it about its new origin
context.transform(tm);        // I snook in a bit here - see below
context.translate(-dx, -dy);  // move centered object to origin

context.stroke();             // render the path
context.restore();
When I actually reached this point of enlightenment, I still had difficulty believing that the stroked path would be suitably modified, but it is!

In the list of transformation operations above, I snook in a context.transform(). For some reason, Cairo Context does not provide for the transformation operations usually described as 'flip', and skew/shear. It does however provide the transform() method that allows you to specify the matrix that should be included in the multiplication chain. For flip and shear, the matrices look something like this, where tm is a cairo.Matrix:


if (thflip)  // flip top to bottom
{
   tm.init(-1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
   c.transform(tm);
}
if (tvflip)  // left/right
{
   tm.init(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
   c.transform(tm);
}
if (tshear != 0.0)
{
   // this is x-axis shear - to do y-axis shear I think
   // you just move the double tshear argument to be
   // second rather than third.
   tm.init(1.0, 0.0, tshear,1.0, 0.0, 0.0);
   c.transform(tm);
}
So if you can work out what I'm saying, then you can apply some weird and wonderful effects to whatever path you are rendering. In some cases you might wish that path to represent text outlines. I'll get to that in another post.
13/8/2011 - Using gtkD - Copying a TextBuffer.

This is another of those things that can slow you down for a while. Easy when you know how.

Getting the text is a snip - you can just call tb.getText(), but that just gives you a string. In what I'm writing, the user can select different fonts and colors for separate parts of the text, so you want all the TextBuffer tag information as well.

I decided I'd serialize it, then deserialize it, which the documentation says you can do. But it turns out there are a few non-obvious caveats. Here's what works for me.

First you have to take a step back, and revisit the code where the user sets fonts and colors for bits of the text. You can do this quite easily by just applying a Tag to the current selection in the TextView. But to support deserialization, the tags may need to have names. I just added a static uint to the class I was working with, then made a trivial unique tag name using the next value of that.


static uint tagId;
static uint getTagId() { return tagId++; }
...
TextIter start, end;
start = new TextIter();
end = new TextIter();
TextBuffer tb = textview.getBuffer();
if (tb.getSelectionBounds(start, end))
{
   string tagName = "T" ~ to!string(id);
   TextTag tt = tb.createTag(tagName, "font", fname);
   tb.applyTag(tt, start, end);
}
The actual copying bit goes like this:

// Copy tb1 into tb2
TextIter start = new TextIter();
TextIter end = new TextIter();
tb1.getBounds(start, end);

GdkAtom atomsource = tb1.registerSerializeTagset(null);
GdkAtom atomdest = tb2.registerDeserializeTagset(null);

ubyte[] buffer = tb1.serialize(tb1, atomsource, start, end);
tb2.getIterAtOffset(start, 0);
tb2.deserializeSetCanCreateTags (atomdest, 1);
tb2.deserialize(tb2, atomdest, start, buffer);
6/8/2011 - Using gtkD: Setting a Focus After TreeView Selection.

I'd been tolerating a fault in my application on the grounds that the solution was trivial, and I'd get to it, so today I did. The fault was that that when I selected an item from my TreeView corresponding to an object that would display a TextView, the focus was not being set to the latter - I had to actually click in it before entering text.

Wrong! It's not trivial, but fortunately I found a Python discussion thread that went through this rather tortuously, and I managed to convert that into D.

I have a selection change handler that changes my selected object, and needed to start there:


static extern(C) int onTreeSelect(GtkTreeSelection* ts, GtkTreeModel* m, GtkTreePath* p,
                                  int isSelected, void* userData)
{
   if (isSelected)
      return 1;
   MainWindow mw = cast(MainWindow) userData;

   // Make the object indicated by the selected row the current object
   ...
   // Now the focus should be set to the object, which has a virtual
   // focus() method that does a grabFocus() where there's a TextView involved.

   // Add a handler for selection change to be called after the selection
   // change is a done deal.
   TreeSelection tso = new TreeSelection(ts);
   tso.addOnChanged(&mw.onTVSelectionChanged, GConnectFlags.AFTER);
   return 1;
}
Now if I simply make the handler - onTVSelectionChanged - call the focus() method for the currently selected object, that does not work. The event timings are presumably wrong. Instead, I need to set up another handler to be called in an idle loop:

static extern(C) bool idleFunc(void* vp)
{
   // This handler gets the currently selected object passed
   ACBase x = cast(ACBase) vp;
   x.focus();

   // The return false is important - it means just call this
   // function once!
   return false;
}

void onTVSelectionChanged(TreeSelection ts)
{
   // import glib.Idle

   // Put the handler 'idleFunc' into the idle loop handler chain, passing
   // the currently selected object.
   Idle.add(cast(GSourceFunc) &idleFunc, cast(void*) cto);
}
And there was I thinking I just needed to stick 'whatever.setFocus()' somewhere in my code. You live and learn! You can read the official documentation about the idle loop handling here.
5/8/2011 - Using gtkD: Caching Content of a Cairo Context.

The piece I'm working on is one of those typical OO drawing applications where a succession of objects each render their own thing to a graphical context, thus building up a composition.

When I'm showing the design view for a particular object, I want the user to be able to drag the item rendered by that particular object around and to see it in the context of the other objects in the composition.

When doing a mouse drag, you need to do as little rendering and associated computation as possible to get a smooth effect, so I decided that when the design view was first exposed, I would get all the other objects to do their thing, then cache the result in a way that could be efficiently 'blitted' onto the design context. I would then draw the target object on top of that. So when a move was required all that would be necessary would be to blit on the background again and just render the one object.

After some reading around I discovered what seems to be the proper Cairo way of doing this. Here's how it goes:


bool exposeCallback(GdkEventExpose* event, Widget widget)
{
   // The Container here is a tree item that has a number of children
   // that each render a contribution to the composition
   Container parent = cast(Container) parent;
   // The entity we're drawing on is a DrawingArea widget
   // For our actual rendering we must create a cairo.Context for that.
   Drawable dr = da.getWindow();
   Context c = new Context (dr);

   // Check if we have already cached the background for this design view
   if (background is null)
   {
      // background is a gtk.Surface object - all these objects have one.
      background =
         c.getTarget().createSimilar(cairo_content_t.COLOR_ALPHA, cWidth, cHeight);
      // Get a gtk.Context for the background Surface
      Context t = c.create(background);

      // We now get the container to render all of its children to the Surface
      // except for this one
      parent.renderOther(this, t);
   }

   // Standard stuff
   if (event)
   {
      // clip to the area indicated by the expose event so that we only redraw
      // the portion of the window that needs to be redrawn
      c.rectangle(event.area.x, event.area.y,
         event.area.width, event.area.height);
      c.clip();
   }
   c.save();
   // Now blit the already painted background into the design view context
   c.setSourceSurface(background, 0, 0);
   c.paint();
   c.restore();

   // Then we can render the current object on top of it.
   designRender(c);

   return true;
}
Hope this proves to be useful - enjoy!
4/8/2011 - Using gtkD: TreeView columns with a CheckBox.

Having got gtkD to build with the latest Linux version of DMD I plunged into something that has turned out to be quite challenging. The GTK documentation, both that which comes with gtkD, and that available for the 'C' version, and other language bindings, can be a bit thin. Having said that, I must also say that for the most part, gtkD has stood up to my efforts very well. I've made a few tweaks to the implementation to make it easier to use for what I'm doing, and hopefully I'll cover those later.

One of the things that bogged me down for some time was getting the GTK TreeView widget to not only display check-boxes in one of its columns, but also to allow me to set and unset them.

I wanted to do this in a way that would allow me to select tree rows in the usual way - a simple left click on the identification columns, but also to be able to click and toggle the check-box without selecting the row.

I think that my two primary stumbling blocks were first a piece of stupidity on my part, and second, a misunderstanding of the nature of one of the attributes used in TreeView column creation.

The implementation of TreeModel is quite well described in a number of web articles. My stupid mistake there arose when I added the check-box column, and failed to correctly specify the type of the column. Do remember when you are returning a value for the check-box column that it is boolean:


override Value getValue(TreeIter iter, int column, Value value)
{
   // whatever
   value.init(GType.BOOLEAN);    // simply using setBoolean is not sufficient
   value.setBoolean(someBooleanValue);

   return value;
}
In a previous version of my stuff where I had got the TreeView working OK with just two string type columns, there were attribute settings:

col = new TreeViewColumn();
renderer  = new CellRendererText();
col.packStart(renderer, true);
col.addAttribute(renderer, "text", 1);
col.setTitle("Name");
view.appendColumn(col);

col = new TreeViewColumn();
renderer  = new CellRendererText();
col.packStart(renderer, true);
col.addAttribute(renderer, "text", 2);
col.setTitle("Type");
view.appendColumn(col);
The relevant bits here are "text", 1 and "text, 2 - this is column one and it's a string column, and similar for column 2. Now in web articles about toggle columns I'd seen the attribute "active" set, and unfortunately, the accompanying value there was as in "active", 1. I had wrongly assumed that this set the 'sensitivity' of the column. But no - "active" appears to be equivalent to "text", in that it describes the type of the column, and maybe it should have been "toggle" or something. Eventually the penny dropped and I realized that my first column needed:

col = new TreeViewColumn();
rtog = new CellRendererToggle();
col.packStart(rtog, false);
col.addAttribute(rtog, "active", 0); // "active", 0 means column 0 is a 'toggle'
col.setTitle("Active");
view.appendColumn(col);
So then there was the question of the mouse click code. Here, what worked for me was:

bool onTreeClick(GdkEventButton* event, Widget t)
{
   if (event.type == GdkEventType.BUTTON_PRESS  &&  event.button == 1)
   {
      TreePath tp;
      TreeViewColumn tvc;
      int cellX, cellY;
      // The TreeView is tv, the model is tm
      tv.getPathAtPos (cast(int) event.x, cast(int) event.y, tp, tvc, cellX, cellY);
      if (tvc.getTitle() != "Active")
         return false;  // We didn't handle it, so just a normal select
      TreeIter ti = new TreeIter();
      tm.getIter(ti, tp);
      ACBase x = cast(ACBase)ti.userData;  // The base type from my TreeModel
      x.setOthersInactive(); // Note that this is 'the one' and eliminate others
      tv.queueDraw(); // request a repaint
   }
   return true;
}
I hope the hints here may help others over similar hurdles.
20/7/2011 - Building gtkD.

For a complicated set of reasons I tried to install 'gtkD' a D programming language wrapper for GTK+ - the library that provides the GUI widgets for Gnome-based Linux distributions. Of course, I can only speak for Ubuntu - 11.04 to be precise.

I downloaded the latest version of the stuff - gtkD-1.4.1.zip from http://www.dsource.org/projects/gtkd. There are a couple of README files, the first of which threatens you with eternal damnation is you don't use some build utility called 'dsss'.

Step one is to install DMD (D Version 2 that is) - the one-click Ubuntu download from Digital Mars did that for me. Step two is to ignore the dsss blurb. In the root directory of the download, there's a file called GNUmakefile. This is close to what you'd expect for a Linux distribution. You can switch to the directory, then invoke 'make', and 'make install'.

The former will fail at a file /gtkD/src/gobject/ObjectD.d. At line 77, you'll find a conditional import like:


version(Tango) {
	private import tango.core.Memory;

	version = druntime;
} else version(D_Version2) {
	private import core.memory;

	version = druntime;
} else {
	private import std.gc;
}
You can just replace this with:

private import core.memory;
I think that some of the pre-defined version strings have been eliminated since D Version 2 became standard D. Further down, at lines 190 and 202, you'll find:

		version(druntime) GC.addRoot(data);
		else std.gc.addRoot(data);
 ...
		version(druntime) GC.removeRoot(data);
		else std.gc.removeRoot(data);
You can just replace those with GC.addRoot(data), and GC.removeRoot(data) - same sort of thing. Then make should complete.

At that point you need to do:


sudo su
make install
This should complete OK, at which point, if you examine /usr/local/lib, you should find you have libgtkdsv.a, libgtkdgl.a, and libgtkd.a.

You can now try to build one of the demo programs. I chose gtkD/demos/gtkD/DemoCustomList. Switch to that directory, then use:


dmd CustomList.d DemoCustomList.d -I/usr/local/include/d -L-lgtkd -L-ldl
Then you should be on your way - seems to work at that point, although it's not what you'd call an inspiring demonstration. If I find out otherwise, I'll update this.
daily stats picture

30 day graphical report.

22/6/2011 - Hits'n Stats Revisited.

I have been working on my web site statistics LAMP application, and as a consequence I have replaced the content of the Hits'n Stats pages.

The new version uses jQuery, and is less ambitious in scope that the original one, which attempted to provide a service to others. Now it is cut down to something just for use on a single web site.

If anyone is interested I will post a gzip of the files shortly.

11/6/2011 - Datatables: Populating via AJAX.

Yet another mini-article in my jQuery.Datatables 'Getting Started' sequence.

It shows how to populate a table from a remote source, and how to re-populate it. There's also some commentary on the alternatives for importing JSON data into a table - text/plain, or application/json.

Row Selection/Marking

Row Selection/Marking.

10/6/2011 - Datatables: Row Selection and Marking.

Here's another snippet of Javascript/CSS coding for my 'Getting Started' sequence.

It shows how to select and mark a row in a table, and the extract the relevant values while you're at it.

Result picture

The initial result.

9/6/2011 - Getting Started With jQuery Datatables.

I started using jQuery.Datatables recently, and was dissapointed with the getting started documentation. Among other things, this says "DataTables has most features enabled by default, so all you need to do to use it with one of your own tables is to call the construction function.

Unfortunately, that does not work as one might have hoped. You can see a typical result in the picture.

Looking at the Datatables forum, it seems that I'm not the only one who had this sensation, so after I'd got it working, I thought I would write a short article that showed how to get from that initial point to something that bears a closer resemblance to the demo pages. You can find the article here.

Tools picture 9/11/2010 - A Couple of Web Tools.

Readers who have watched the BEV home page, and look at this one (at this point it's not clear that these sets intersect) will be aware that for a couple of days I have been working on a hopefully tiny piece of software to generate a site map.

This was to be a quick exercise to enable me to submit a site map to Google. But of course when it comes to computer software 'quick' is one of those elusive qualities. It's too much to describe in a single post here, so I have created a separate Sitemapper page

The tools folder also now has a filter suitable for preparation of code samples for typical highlighters. It replaces ampersand, less-than, and greater-than characters with the appropriate HTML entities, and then lets you quickly and easily replace the contents of the clipboard with the filtered text - just paste and click.

It uses Google's ZeroClipboard to accomplish the clipboard re-population.

28/10/2010 - A Simple CAPTCHA Device for Low-Profile Web Pages.

I wanted to put some measure of protection against robot clients into the feedback system I use on various pages. As it is, any schoolboy could write a simple robot to fill my database with junk. I'm sure that there are many heavyweight solutions out there, but as always, I had the urge to do something myself.

So I wrote myself a little PHP script to render a very simple picture of an analogue clock, given hour and minute parameters. I include the image in my TFC UI. Given that, the security sequence is:

  1. When the component is invoked, it notes the current time as seconds since 1970. I guess it could equally well generate a random number.
  2. The time is sent as a query variable in the PHP get that fetches the clock image.
  3. The clock script takes the get parameter, and MD5 hashes it with a couple of (hopefully) secret pass phrases, to make a HEX string.
  4. It then extracts eight characters from the MD5 string, and parses them as an integer N from which it extracts (N >> 16)%12 as the hour, and ((N & 0xffff)%12)*5 as the minute. From these it renders the clock picture.
  5. When the comment is submitted, the same time number, and the users rendition of what it says on the clock are sent along with the comment information.
  6. The PHP script that saves comments repeats the activity of the clock script to convert the submitted time (the seconds since 1970) to an hour and a minute. These are compared to the hour and minute rendered by the user. If they agree, the comment is written to the database.
  7. If they don't agree, the request is bounced, the UI then notes the time again, and a new clock image is requested based on that, so the user, or robot, only gets one shot at any particular clock.
I can describe in detail how it works because I believe it is just a simple application of hashing. The robot must either discover the passwords used to generate the hash, or learn to read my clock picture. I'm assuming that most casual assailants won't have the time or energy to do the latter for a web site as unimportant as mine.

Will some security buff out there please let me know how long it would take to break this system.

28/10/2010 - BEV Tiny Feedback Component as a jQuery Plugin.

I have now made my Tiny Feedback Component, TFC, into a jQuery plugin - yes I have become a jQuery addict. Download it here. So at this point I thought I should do a proper job of documenting how to use it, should anyone want to.

First the environment. TFC expects to live in a typical LAMP hosted web site environment, where there is localhost access to a MySQL database, and PHP is installed. Most of the setup is in uploading the required PHP files, and creating the database table. The PHP files are included in the download, and comprise:

  • clock.php
  • createcomtab.php
  • gettopics.php
  • listcomments.php
  • purgecoms.php
  • savecomment2.php
  • dbcommon.inc
You'll need to tweak dbcommon.inc to relect you database name and suitable logon information. While you are at it, make sure your .htaccess file is set up to prevent listing of the PHP directory, and to be sure, add an index.html file to it with some rude message. I actually use a page that logs the attempted access to TFC.

When you've done that, navigate to http://yoursite.xxx/php/createcomtab.php, and thus create the required database table.

There's one more file to upload to your script directory - jquery-bevtfc.js. To see if all is well, you can also upload the the TFC test page to your site, modify it as indicated below, and then access it. Copy the source code from the demo.

Then to add TFC to your page or pages, you'll need to follow the following steps, referring to the following source snippets as you go. First in you <head> section:


<script src="../script/jquery.js" type="text/javascript"></script>
<script src="../script/jquery-bevtfc.js" type="text/javascript"></script>

<script type="text/javascript">
//<![CDATA[

// Example only
var _britseyeview_reader_city = "New York";
var _britseyeview_reader_region = "NY";
var _britseyeview_reader_country = "USA";
$(function() {
    $("#TFC-toggler").bevTfc(
       {
          divid: "TFC-outerdiv",               // id of a div that the component will be placed in
          site: "http://www.britseyeview.com", // your canonical address
          category: "TFCTest",                 // identifier for the page where TFC is being included
          title: "Have your say",              // title for the TFC dialog
          surl: "/php/savecomment2.php",       // paths  to PHP files
          rurl: "/php/listcomments.php",
          turl: "/php/gettopics.php",
          curl: "/php/clock.php",
          useLocInfo: true,   // set to false if you don't have any reader location information
          noToggle: false     // if this is set to true, the dialog will be permanently displayed
                              // In that case call with e.g. $("#TFC-outerdiv") as a dummy target
       },
       {
          cityVar: "_britseyeview_reader_city",
          regionVar: "_britseyeview_reader_region",
          countryVar: "_britseyeview_reader_country"
       }
    );
});
//]]>
</script>
  1. Add a script include to your head section after the jQuery include.
  2. In the document-ready section, include a more or less conventional jQuery plugin instantiation.
  3. Change the settings in the initialization parameters object to reflect your web address, page identifier, the title you want, and the locations of the PHP files.
  4. If your site has information about the location of visitors, set up the options object to tell TFC where it can find city, region, and country.
Instead of the usual single options object that can override default settings, TFC requires a parameters object. This contains information that is necessary to make it work. Then there's an options object that will eventually be able to override default settings. This is very limited at present.

Then in the body of your page:

  1. Add a vanilla <div> with an ID of your choosing. This is where TFC will get placed. Allow for it being 800px wide.
  2. Add or choose a tag that will be made click-able by the initialization.

<body>
<h3 id="TFC-toggler" style="cursor:pointer;">Have your say</h3>
<div id="TFC-outerdiv"></div>
</body>
You'll notice that this version has a simple CAPTCHA device included. There's a picture of a analogue clock showing some unrelated time, that the user must translate into text before submitting a comment. I'll describe it in my next post.
26/10/2010 - Javascript Prototypal Inheritance and 'Class" Hierarchies.

Guru Crockford's most recent statement on Prototypal Inheritance was that he preferred an approach like:


if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);
This still messes with one of JavaScript's fundamental entities, and it sidesteps the issue of how you would actually create instances of derived 'classes' using some sort of constructor that was passed the class instance properties, and the values of the instance properties of its base class. However, it does not preclude this capability.

I decided to have a play with this (pardon the pun), using my favourite hierarchy example - shapes.

A very simple base class could just embody position information. Using the ubiquitous '$' character to distinctively mark constructors, we could have:


function $Shape(x, y)
{
   this.x = x;
   this.y = y;
   this.draw = function() { alert(this.x+", "+this.y); };
}

// Then we can do
var proto = new $Shape(0, 0);
proto.draw();   // alerts "0, 0"
Now we need a constructor for a rectangle object. We will wrap Crockford's technique within that. It needs to get arguments to allow it to inherit from Shape, and its position width, and height:

function $Rectangle(base, x, y, width, height)
{
   base.x = x; base.y = y;
   function f(w, h) { this.width = w; this.height = h; }
   f.prototype = cloneObj(base);  // My highlighter does not think prototype is a keyword
   var that =  new f(width, height);
   that.draw = function() { alert(this.x+', '+this.y+', '+this.width+', '+this.height); }
   return that;
}
We pass an exemplar base object as the first argument, and the other stuff as you'd expect. We must then copy the exemplar object, so that we're not using a shared prototype for all instances of Rectangle objects - if we did, they would all be drawn at the same position. Once we have a specific base class instance, we then tweak its properties to reflect the position we want.

The function f() will create an object that knows about the width and height values. Having defined it, we give it the tweaked base type object as a prototype so it also has the position information.

Then we create the object using new, and override its report() method. What surprises me about this is that the references to 'this' in the new report function are actually accepted by the compiler - there is no 'this' in the $Rectangle function. I guess the compiler just accepts that the function being defined is to be called with a context.

Having done that, we can now write


var rect = $Rectangle(proto, 3, 4, 5, 6);
rect.draw(); // alerts '3, 4, 5. 6'
and Bingo, it does what we expect.

Now if we could eliminate the need to pass a specific object as the base class, it would start to look quite civilized. I thought this could be done if the library that implements your Shape hierarchy is all defined in one big anonymous closure (whoops - so it is like Java after all ;=)). Then the prototypes can be private local variables within the closure, and the individual constructors can be implemented with no explicit base class argument, though they will of course need some sort of object as a context - just as Crockford's method uses Object. So here goes:


var Shapes = (function() {
var shapes = {};

function cloneObj(o)
{
   if(typeof(o) != 'object') return o;
   if(o == null) return o;

   var newO = new Object();

   for(var i in o) { newO[i] = cloneObj(o[i]); }
   return newO;
}

function $Shape(x, y)
{
   this.x = x;
   this.y = y;
   this.draw = function() { alert(this.x+", "+this.y); };
}

var proto = new $Shape(0, 0);

function $Rectangle(x, y, width, height)
{
   proto.x = x; proto.y = y;
   function f(w, h) { this.width = w; this.height = h; }
   f.prototype = cloneObj(proto);
   var that =  new f(width, height);
   that.draw = function() { alert(this.x+', '+this.y+', '+this.width+', '+this.height); }
   return that;
}

shapes.$Rectangle = $Rectangle;
return shapes;
})();

var r1 = Shapes.$Rectangle(3, 4, 5, 6);
r1.draw();
var r2 = Shapes.$Rectangle(10,10,1,1);
r2.draw();
r1.draw();
The context object for the constructors now represents the hierarchy as a whole, which is quite semantically satisfying. This approach has the added benefit of hiding the rather useless base class that just wraps position - you could say it is now an 'abstract base class'.

I should note that I have only tested this with the JS compiler in Firefox. Feedback on other compilers would be appreciated. Also I thank Andrew Sellick for the cloneObj function. It's tempting to think of adding that to Object.prototype.

An alternative clone function can be based on the Crockford approach:


function cloneObj(o)
{
    function F() {}
    F.prototype = o;
    return new F();
}
21/10/2010 - Bold Keywords in Highlight.js.

The code highlighter I'm using on this page is Highlighter.js, which I really like because of it's intelligent detection of languages, it ascetic simplicity, and its speed.

In Firefox, the result looked great 'out-of-the-box', but in IE8, my JavaScript highlighting looked like shit. The keywords are supposed to be black+bold, but IE renders them as virtually indistinguishable from normal text.

Someone on the Hihglighter.js forum was most helpful, pointing out to me that this is a feature of the IE default <code> font at small sizes. To get it looking OK in IE, I had to tweak the Highlighter.js default CSS file to suggest the use of Lucida Console. Then it looks OK in IE, but looks like shit on my Ubuntu development machine - the Lucida Console is a bit iffy there (10.04). So finally the trick is that you need to find a monospace font that Ubuntu (and hopefully other Linux variants) has, and Windows doesn't. Then you can suggest the Linux font first.

My other tiny gripe about Highlighter.js' default settings is that the <pre><code> text is too widely margined/padded. My final effort was to set the style for PRE to { padding:0px; margin:0px; } explicitly in my page source, then set my exact preferences in the CSS file. I now have:


pre code {
  display: block; padding-bottom:0.5em;
  font-family:dejavu sans mono,lucida console,monospace;
  margin-top:0.5em; margin-bottom:0.3em;
  background: #e8e8e8;
}
You can see what goes on with the fonts if you check out the source from the IFRAME below in IE8 and Firefox:

20/10/2010 - jQuery Plugin Alternatives Example.

A few days ago I illustrated the method of creating a jQuery plugin where the following technique is used:


(function( $ ) {
   $.fn.hScroll = function() { ... };
})( jQuery );
There is of course an alternative. You can do smething like:

(function( $ ) {
   $.somethingElse = function() { ... };
})( jQuery );
Where you attach a new method directly to the actual jQuery object. It's all down to the way you decide you want to provide context information to a function, as in:

myObject.memberFunction();      // access to data via this.dataItem
staticFunction(myObject);          // access to data via myObject.dataItem
My example today illustrates the two alternatives.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
var myData = { a: 42, b: "universe" };

(function( $ ){
$.fn.oneWay = function(data)
{
   return this.html("First way - ID of my target is "+this.attr("id")+
                        ", my data is a: '"+data.a+"' b:'"+data.b+"'");
};

$.otherWay = function(target, data)
{
   return $("#"+target).html("Other way - ID of my target is "+
               target+", my data is a: '"+data.a+"' b:'"+data.b+"'");
}
})( jQuery );

$(function()
{
   // There's nothing I want to do at this point, the data is chosen by the user
});
</script>
</head>
<body>
<button onclick="myData = { a: 3.142, b: 'Pi' };">Choose alternate data</button>&nbsp;
<button onclick="$('#target').oneWay(myData).css('backgroundColor', '#aaffaa');">First way</button>&nbsp;
<button onclick="$.otherWay('target', myData).css('backgroundColor', '#ffaaaa');">Other way</button>
<p>
<div id="target" style="width:600px; height:20px; border:solid 1px;">
</div>
</body>
</html>
Here it is:

As you can see, it is a puzzling choice, and I think that at the end of the day it boils down to the look and feel of the semantics you want to achieve. You can get jQuery chaining either way.

17/10/2010 - jQuery Closures

I had reached the point with my pages where I was including jquery.js, so it seemed ridiculous to continue using low-level HTML DOM calls to do what I could do more succinctly in the jQuery environment that was already there. This led me with a certain inevitability toward writing jQuery plugins.

Now there are lots of good plugin tutorials, including the one at jquery.com, but many of them seem to stop before they have covered enough detail, possibly assuming that you know JavaScript well enough to be able to figure it out for yourself. One of my requirements went beyond these, so I had to figure it out. Since I have done so, I should try to promulgate any little thing I have found out.

The plugin in question is one for horizontal scrolling. On my pages, I want to minimize the amount of scrolling down the page that visitors have to do. My solution threw up a few features that are not covered in the primary documentation. In some ways, this is an extension of the stuff you can find on 'Learning jQuery' What is this?".

The plugin I made has no methods that can be called after it is instantiated. It uses the fairly common jQuery techniques of modifying an existing DOM, and attaching event handlers to existing elements. Then it bows out. I will list the code to start with, and then explain.


// The customary anonymous function
(function( $ ) {

// 1. Not very customary, but we are defining a function, so we can define variables that are local to it.
var scrollpos = 0;
var numdivs = 0;
var slider;

// 2. And we can put our default plugin properties in the same scope
var defaults = {
   scrollWidth:800,          // In px
   paneHeight: 1000,       // In px
   hWidth: 20000,           // In em
   itemClass: 'hs-item',
   fwdBtnId: 'hs-fwd',
   bkBtnId: 'hs-bk'
};

// 3. This is straight out of the book, as per the jQuery web page documentation
$.fn.hScroll = function(options)
{
   if (options)
      $.extend(defaults, options);

// 4. But I don't see many examples of this, though nested functions are fine, and like other
//    JavaScript functions they are first-class citizens.
   function scroll(fwd)
   {
      if (fwd)
      {
         if (scrollpos == -defaults.scrollWidth*(numdivs-1))
            return;
         scrollpos -= defaults.scrollWidth;
      }
      else
      {
         if (scrollpos == 0)
            return;
         scrollpos += defaults.scrollWidth;
       }
       var t = { left: '' };
       t.left = scrollpos+"px";
       slider.animate(t, "fast");
   }
   function scrollAbs(n)
   {
       scrollpos = -(numdivs-n)*defaults.scrollWidth;
       slider.css("left", scrollpos+"px")
   }

   // Here we start the implementation bit
   numdivs = this.length;
   this.wrapAll('<div id="hs-slider___" style="width:'+defaults.hWidth+
                        'em; position:absolute; vertical-align:top;" />');
   slider = $('#hs-slider___');
   slider.wrap('<div id="hs-pane___" style="position:relative; overflow:hidden; width:'+
                             defaults.scrollWidth+'px; height:'+defaults.paneHeight+'px;" />');

   // Line up the items within the slider DIV
   $(this).each(function()
   {
      $(this).attr("style", "float: left; vertical-align:top; width:"+defaults.scrollWidth+"px;");
   });

//6.  Now reach out to existing elements to add events that allow us to control this thing
//    Notice that we can pass parameters to the event handler. The JS compiler will make snapshot
//    copies of any data it needs - that's the nature of a closure.
   $("#"+defaults.fwdBtnId).click(function() { scroll(false); });
   $("#"+defaults.bkBtnId).click(function() { scroll(true); });

   // Find things that might want to scroll to a particular item directly - more snapshot data.
   $(".hs-link").each(function()
   {
       var n = parseInt(this.id.substring(1));
       $(this).click(function() { scrollAbs(n); });
   });
};
})( jQuery );
This whole thing is wrapped in the

(function( $ ) {
...
})( jQuery );
thing that is generally described in the jQuery documentation as a closure. But I want to be a little pedantic about that. In this case, it is a closure, because at several points we hand out the addresses of functions. The fact that we use the wrapper though is not sufficient for the construct to qualify as a closure.

If all we did within it was to change the background colour of a few elements, then there would be no need for the compiler to treat it as a closure. All state information could be dumped as soon as the execution of the anonymous function completed. To be even more pedantic, a really clever compiler would also be able to figure out if a function that was handed out referred to any state variables within the wrapper. If it didn't, then the same applies - state information could be dumped. I think that in practice, most compilers for languages that support closures will retain the state information if a function address is handed out.

To expand on my numbered comments:

  1. Most examples don't illustrate this, but the anonymous function is just like any other. We can define local variables before or in between executable instructions.
  2. That includes our customizable parameters - they are just variables like any other.
  3. Here we have made this into a closure, since we have handed out the address of a function.
  4. The scroll() function is nested within the main function here. I would work just as well if we had defined it in the same context as the variables like scrollpos.
  5. Here we hand out more functions as event handlers, As we do so, the compiler is obliged to take snapshots of the current state, so that the arguments to the nested functions are effectively reduced to constants each time we hand out a handler.
If you can see this, you probably have JavaScript disabled, and BEV 3 will not work as designed."

Squash This List

What is BEV?

Brits Eye View is an Englishman's personal blog, started in January 2003. It's currently about life in Arusha (Tanzania), and previously in Bangalore, Manhattan, and the Bronx. It deals with life in general, building a house, food and drink, computer programming, opinion on current affairs, 20th century history, and so on. It may give you some insight into what life is like in 'the third world', or encourage you to visit Tanzania.

There is also a retrospective view of the latter half of the 20th century, currently spanning 1942 - 1975 so far.

My wife and I run a small but very pleasant guest house in Arusha - Adia's Place - check it out!

To list the posts available on this blog, click the next list item to expand it.

Software Blog Postings List.

This page was becoming unmanageably large, so I have split of most of the older postings into a separate page that you can find here. That has postings back to October 2009. Here is the more recent stuff.

Why a Software Page?

Well, I was involved with computer programming from the late 60s onward, spanning early FORTRAN to D.

I retired in 2007, but somehow I can't get out of the habit, and still get occasional flashes of "I wonder what would happen if?", or "How do they do that?", or libraries that don't work and I have to fix for myself.

GDC Newbie Summary.

I spent some time earlier this year (2010) attempting to create a version of the GDC compiler for the D programming language, based on GCC - the Gnu Compiler Connection. I was new to GCC and existing versions of GDC at the time, so I started to keep a record of the things I discovered. The results are here.

I was successful to a degree, but as with many other things I've done, there was a resounding lack of interest, so I did not feel it was worth continuing. The work I did was subsequently used by one of the Ubuntu contributors - Iain Buclaw - to make a GCC 4.4 based compiler for D version 1.

DCat Summary.

For a long time I had this idea of writing a web application server in a compiled language that would be in the same general class to its language as TomCat is to Java. It's additional feature was that a web application, or set of applications would have the inter-page logic defined entirely in XML.

I tried it years ago in C++, using FastCGI, and got quite a long way, but nobody was interested. Then when I got into the D programming language, I thought I would have another go, this time with a D implementation of the AJP13 protocol between the web server and the application engine.

I got quite a long way with that too, but was stymied by the lack of capability of D to produce and dynamically load DLLs or shared libraries, or to dynamically load object files.

DCat has a set of associated D utility classes for things like logging, Windows event logging, property files, parsing XML, creating a Windows service, and so on.

You can read more about it here, see its (now somewhat outdated) changelog, or download a zip file for the Windows version.

Hits'n Stats Summary.

I used to use a third party hit counting service on the BEV pages, but it did not really do what I wanted. So I rolled my own

Hits'n Stats has less focus on hit counting, and more on discovering who your readers are, and presenting that information in a simple and convenient form.

It's written for the classic PHP/MySQL combination, so it's easy to install on most shared hosting systems.

You can read more about it here. Using the pages referenced here, you can sign yourself up to try out the system on your own site. If you want to use it, get in touch, I have not put together a distribution of it yet.

TFC-Tiny Feedback Component.

I tried a variety of ways of collecting feedback from users: A bulletin board, and a news-reader approach, but they got hacked, or the newsgroup magically disappeared or something. So once again I did my own thing.

You can click on the 'Comment' link in the toolbar to see what it does.

It's written for the classic PHP/MySQL combination, so it's easy to install on most shared hosting systems.

You can read more about it here, and download a zip file.

You can get the general idea from these, but if you want the latest stuff that works with jQuery, and has some other changes, please email me. I will do a revised document when I have reimplemented it as a jQuery plug-in.

MySqlD.

This is the DDocs generated documentation for a set of classes in the D programming language that constitute a wrapper around the MySql C library.

You can get the source code and the other bits you need to build and set up MySqlD here.

Publicity Summary.

At the beginning of the 90s, the only Windows application that specialized in printing labels, business cards and such, was one called Avery Labelpro. I did not think that it was particularly good, so I tried to do better

A lot of people thought I succeeded, but I failed to sell enough copies to stay in business with it - didn't have the financing for advertising etc. So eventually it became freeware. It is definitely legacy software, and I don't support it any more, but is still quite good at what it does. You can read more about it here, view its user documentation, or download a setup executable.