OpenOffice and basic collaboration

I use OpenOffice as my office tools suite. For my needs -- letters, documentation, and budgets -- it is more than adequate. The one area where it is not nearly as good as Microsoft Office during collaborative writing and editing. Word's balloon comments really makes it easy to add and review comments and maintain the integrity of the original document.

I did find one feature in OpenOffice recently that helps collaboration though and that is line numbers. OpenOffice will automatically add and maintain line numbers in the left margin. This feature makes referencing the content in text -- email, IM, etc -- and in person -- meetings, phone, skype, etc -- straigh forward. I wish Word had this feature. Then again, perhaps it does and just have not yet found it.

Using inline HTML as templates

I was tired of embeding HTML inside Javascript: How many times have you gotten right on the first try
var template = '<p id="'+base_id+'-a">This is the template. ' + 
  '<b id="'+base_id+'-b">And this is the tempalate, too.</b></p>';

Where as we always seem to get right
<p id="xxx-a">
  This is the template. <b id="xxx-b">And this is the tempalate, too.</b>
</p>

So, instead I wanted to place the HTML inline in the document and clone it from Javascript when needed. This allowed me to more easily code and then syntactically and visually check the HTML by rendering in the browser.

Unfortunately, there is no deep clone for DOM elements. And even if there was one I suspect it would not handle ID attributes as I wanted. So I wrote my own clone_dom and clone_dom_element functions.


<html>
<head>
<script type="text/javascript" src="http://prototypejs.org/javascripts/prototype.js"></script>
<script type="text/javascript">

  /*
   * clone_dom
   *
   * clone's the DOM element tree starting at template_id and appends to
   * element at target_id. The id_map is a simple hash that maps an id in
   * the template elements to an id in the cloned elements.
   */
  function clone_dom( template_id, target_id, id_map ) {
    var clone_template = clone_dom_element( $(template_id), id_map );
    $(target_id).appendChild( clone_template );
  }

  /*
   * clone_dom_element
   *
   * Clone's and returns the DOM element tree. The id_map is a simple hash
   * that maps an id in the template elements to an id in the cloned elements.
   */
  function clone_dom_element( element, id_map ) {
    var clone_element = element.cloneNode(false);
    if ( clone_element.getAttribute ) {
      var id = clone_element.getAttribute('id');
      if ( id != null ) {
        if ( id_map[id] ) {
          clone_element.setAttribute('id', id_map[id]);
        }
        else {
          clone_element.removeAttribute('id')
        }
      }
    }
    var child_nodes = element.childNodes
    for( var i = 0; i < child_nodes.length; i++ ) {
      var clone_node = clone_dom_element( child_nodes[i], id_map );
      clone_element.appendChild( clone_node );
    }
    return clone_element;
  }

</script>
</head>
<body>

  <!-- Place the templates in a non-displaying part of the document. Since the
     templates will be used in building the document keep them near the top.
     (When debugging the templates display them.)
  -->
  <div id="templates" style="display: none">

    <p id="template-a">
      This is the template. <b id="a-b">And this is the tempalate, too.</b>
    </p>

    <p id="template-x">
      <table border="1">
        <tr><th>Column 1</th><th>Column 2</th></tr>
        <tr><td>Value 1</td><td>Value 2</td></tr>
      </table>
    </p>

  </div>


  <p>Something before the cloned elements</p>

  <!-- There is where the templated DOM will be placed when cloned
  -->
  <div id="location-m"></div>

  <p>Something after the cloned elements</p>

  <!-- We are going to clone template-a and template-x into location-m
  -->
  <script type="text/javascript">
    clone_dom( 'template-a', 'location-m', { 'template-a': 'foo1', 'a-b': 'bar1' } );
    clone_dom( 'template-x', 'location-m', { 'template-x': 'foo2'                } );
    clone_dom( 'template-a', 'location-m', { 'template-a': 'foo3', 'a-b': 'bar3' } );
    clone_dom( 'template-x', 'location-m', { 'template-x': 'foo4'                } );
  </script>

</body>
</html>

What is the right framework for modern application development?

Everyone I know who might have contract work is getting an email from me these days! In my email to David Ascher of Mozilla Messaging I wrote
[...] my time at the start up was all Ruby on Rails .. which I grew to like .. but it is still the wrong language and framework for modern development.
to which David said
Can you explain your last bit?
Here is my attempt to do so.

Google Maps and then GMail significantly raised the expectations of web applications. Today, tools like GWT are raising it even higher. Tools on the web are in one of two classes:

1) sequential data access or
2) compound data use.

Rails and its imitators deal well with sequential data access. They are the GUI of REST. You have a canonical URL that represents the state of the application and the UI. For compound data use, however, you don't always have a canonical URL that represents the state of the application.

Ask the question "What is the URL for the state of my Thunderbird use right now?". As engineers we can imagine a nastly URL composed of very many parameters. A veritable URL maze. But we also know that this is not what is needed.

So, what is needed for modern development?

1) Rich GUI front-end tools as good as Apple's Interface Builder or at least as good as NetBean's Matisse and what Visual Studio has in it today. Apple, Microsoft, Sun and Qt Software (TrollTech) all have the advantage (today) of have an established user interface toolkit (the look) and user interface guidelines (the feel). For web applications this is missing today. There are lots of players attempting to provide this at the DHTML level (css + html + javascript), but I think what is really needed is a new browser standard akin to XUL, and, perhaps, Java Faces, Java Portlets, and even the "widget" ecology.

2) SOA and RESTful backend support of the GUI. This can be done today with all the web application toolkits like Rails, Grails, Django, Joomla, JSTL, etc. and workflow tools like BEPL. Most of this backend support can be stateless and so scale using common techniques and tools.

3) The last item is just the stuff that connects the GUI and the backend. While the developer should always be aware of the network between the two, I don't think the developer need be concerned about how data is marshaled and transmitted. I am not sure how this would be manifested. What Interface Builder and Qt have -- slots, channels, interface points, etc -- would be a useful line of inquiry.

I am generally out of the loop these days when it comes to cutting-edge UI frameworks. What I see in the open-source world though is inadequate. GWT is the torchbearer today but even here the tool pales in comparison to Interface Builder and what the SmallTalk and Lisp worlds have had for decades!

I realize I did not answer the question about language. I am sure Ruby is not it but it is better than many other languages in its language category.

Poems for a new President

Poems have been flowing from blogs since inauguration day. Perhaps someone will collect them to share with all. In the interim, here are two I know of: David Floyd's Inauguration Day and Rethabile Masilo's RICHARD OF YORK GAVE BATTLE IN VAIN.

Update: Here is Elizabeth Alexander's "Praise Song for the Day".

Somewhere in Texas...

Somewhere in Texas the secret-service is returning the village's missing idiot.

South Kingstown, RI Now blog



I am engaged in changing the way the South Kingstown town and school administration keeps us -- the members of the South Kingstown community -- aware of their activities. I believe that with awareness will come increased participation. Today I created the South Kingstown, RI Now blog to record of ideas and communications.

Creating rooted Windows Explorer windows

I like to use "rooted" Windows Explorer windows. A rooted explorer window does not show a folder's ancestors nor any other drives, Desktop, etc. You just see the folder and its decedents. For example, running "explorer /e,/root,c:\Program Files\Internet Explorer" from the command line (or the start menu's "Run..." menu item) will open a root explorer window. The "Internet Explorer" folder's content is on the right and the folder's decedent folders is on the left. Having many of these rooted explores seems to help me keep my desktop organized.

However, I don't want to have to use the command line to create these rooted explorers. I wanted a little GUI that would present a folder section dialog and then have it run explorer for the selected folder. I did this using Windows Scripting Host (WSH) because I knew it could do what I wanted and that everyone could use the result because everyone with Windows XP (and I assume Vista) has WSH. What I did not know how to do was how to program WSH.

When you don't know how to use a language or toolkit and you want to code something really quickly it is best to find code that does something similar to what you want and then hack it. I was lucky and found some sample code and below is the result. Save the code to the file "explore.vbe" and to run it just open it -- I have a shortcut in my Quick Launch toolbar.

set shell = WScript.CreateObject("WScript.Shell")
shell.run "explorer.exe /e,/root," & BrowseForFolder("Windows Explorer Root")

Function BrowseForFolder(strPrompt)
'Uses the "Shell.Application" (only present in Win98 and newer)
'to bring up a file/folder selection window. Falls back to an
'ugly input box under Win95.
'Shell32.ShellSpecialFolderConstants
Const ssfPERSONAL = 5 'My Documents
Const ssfDRIVES = 17 'My Computer
Const SFVVO_SHOWALLOBJECTS = 1
Const SFVVO_SHOWEXTENSIONS = 2
Dim sh, fol, fs, lngView, strPath
Set sh = CreateObject("Shell.Application")
If Instr(TypeName(sh), "Shell") = 0 Then
BrowseForFolder = InputBox(strPrompt, "Select Folder", CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName))
Exit Function
End If
Set fs = CreateObject("Scripting.FileSystemObject")
lngView = SFVVO_SHOWALLOBJECTS Or SFVVO_SHOWEXTENSIONS
strPath = ""
Set fol = sh.BrowseForFolder(&0, strPrompt, lngView, ssfDRIVES)
Err.Clear
On Error Resume Next
strPath = fol.ParentFolder.ParseName(fol.Title).Path
'An error occurs if the user selects a drive instead of a folder
If Err.Number <> 0 Then
BrowseForFolder = Left(Right(fol.Title, 3), 2) & "\"
Else
BrowseForFolder = strPath
End If
End Function
Wow, this is ugly code. But it does work.

Will code for money

I am looking for full-time or contract work. If you are interested in hiring me or just want to chat please send email to andrew@andrewgilmartin.com.

I left WaveSyndicate, a very early stage startup, because as its product was more solidly defined the product became less interesting to me. When this happens, it is always better to leave as soon as this is clear. I believe WaveSyndicate and its product have a good future and especially so with Jared Rosoff and Bob Chatham at the helm.

What emoticon would your grandfather use?

My grandfather was an iron worker in the ship-yards of Glasgow, Scotland. His job was to bore holes 4in thick steal plates that were used in the ship's boilers. I suspect he would have no use for iChat's emoticons.

Participation starts with awareness

For me participation in South Kingstown municipal government and school administration starts with awareness. What is happening right now in town and school? For example, did you know that the engineering drawings for the bathrooms on main st & bike path are complete and implementation is waiting on state funding (promised but now on hold)? Perhaps you are an avid bike path user and want to see the bathrooms built in place of buying more open land this year. Being aware of bike path activities would empower you to advocate for this construction. (The town, by the way, already has been able to set aside 29% of the available land for open-space.) When you are aware of what is being considered and what is being acted upon as early as possible then you don't feel blind sided when the change happens nor do you feel that nothing is happening.

You need to be able to subscribe to specific issues, categories of issues, and full text searches of issues. When new data is added to an issue -- a fact, a comment, a data set, a PDF, a GIS layer, etc -- you will be automatically notified. For some issues you want just a weekly summary sent in email on Saturday morning. For other issues you want detail emailed ASAP and an text message sent now.

Github.com's git training

Wave Syndicate is considering bringing in a trainer from Github.com to do some on-site training. (Wave Syndicate doesn't want me deleting the master branch again.) The trainer would do a couple of lecture style trainings and then some small group tutorials. The cost is $2250. Is anyone else interested in attending and sharing the costs? Email me at andrewgilmartin@3roofs.com.