Finally, charred edges!

Many thanks to Shawn Wallace who helped me complete my introduction to using AS220 Lab's Epilog laser cutter this afternoon. I was able to cut 8 building of two different designs on 12" square, 1/16" thick chipboard. Next step is to assemble them to see how accurate mine and SketchUp's measurements are. To be fair, however, the conversion pipeline between the SketchUp drawing on my MacBook and final output to the cutter is very long -- SketchUp to PDF to iDraw to PDF to Corel Draw to Epilog driver to Epilog hardware.

Too Fat Lardies' "Talking Tactics"

For the WWII gaming novice like myself Richard Clark of Too Fat Lardies is writing a serialized tactics tutorial "Talking Tactics." Well worth reading. Currently there are seven parts

  1. Introduction
  2. The patrol phase
  3. Deploying for the attacker
  4. Deploying for the defender
  5. Fire & Movement
  6. Resource placement
  7. Fish & Chips

I will update this posting as more parts are published.

Update: The Lardies have assembled all the postings into a single PDF document. The document is available in the files area of their Yahoo.com mailing list.

Wargames magazines

In the US the wargaming press is limited to three general audience magazines. Perhaps there are more, but I am unaware of them. They are

  • Wargames, Soldiers & Strategy
  • Wargames Illustrated
  • Miniature Wargames (with Battlegames)
Without a doubt your money is well spent on Wargames, Soldiers & Strategy. Its coverage of historical periods, rule sets, battle scenarios, available miniatures, and informative columnists is well rounded. And the Editor seems like a guy you would want a pint and a conversation with. I subscribe and will renew.

Wargames Illustrated was my first wargames magazine subscription. It continues to be a excellent source of inspiration, but its recent purchase by Battlefront Miniatures is clearly changing the weight of page counts from the broad hobby to Flames of War and WWII. I subscribe, but am considering not renewing.

I find Miniature Wargames interesting some of the time, but mostly I find the tone, as best I can describe it, as matronly. A nearby games store has back issues for several past years available and I have bought, read, and find these older issues and under a different Editor more appealing then the current issues. I will not subscribe.

Damn!

SketchUp models and templates

In my posting Dimensions from photographs with perspective I noted that SketchUp is a tool that needs a trained user. Well, I stopped putting off training myself and within a few hours I was quite comfortable with the basics of it. I know enough now to be able to create a building similar to the one photographed in the previous posting, for example

The yellow roof is there to help me orientate myself when viewing the model in elevation only. I also only use parallel projection for all work in 3D.

With the model finished, I used the Flattery plugin to take each face of the model and lay it down on to the XY plane to create a printable template from which to construct the building in the real world. I also experimented with the Unfold plugin and the brilliant Pepakura Designer application, but for my needs Flattery was just right. (Note that Flattery does not yet work with SketchUp 2015.)

I assembled some parts of the building so as to understand first-hand some of the issues that arise from this process. The first issue is simply keeping track of the parts; I would like to be able to automatically number each face so that once flattened I have a reference to the 3D model in place. A consequence of this is that the template should be printed upside down so that the markings are on the back of the face and not on the front. Doing this also leads to the idea of applying the template to patterned materials. I should note that I am not interested in printing features onto the faces -- such as brickwork, shingles, window frames, ivy, or "rising damp" -- as these models will be enhanced with moulded windows, doors, and other dimensional findings, and then painted.

The template was printed on thin card stock and so material thickness was not an issue in assembling. However, the material I plan to be using -- for example, chipboard, plywood, and MDF -- does have thickness and so I am now learning how to incorporate this construction element into the SketchUp design. I found the videos "Sketchup and Laser Cutting: Making Teeth and Slots" (parts one & two) to be very helpful in getting started with adding dimension. (I am not interested in the interlocking teeth as my models will be glued.) The second video also shows how to flatten the model and to adjust the faces to account for material loss during laser-cutting.

Cats are evil creatures that break Ps on the keyboards with their kneading

Cats are evil creatures that break Ps on the keyboards with their kneading. A big thank you to HP for all their helpful product repair support pages.

High School freshman year is a blizzard of handouts, worksheets, and single pages of notes

High School freshman year is a blizzard of handouts, worksheets, and single pages of notes. None of which are dated. None of which use any system of ordering (e.g., "handout 21 of 97"). I am appalled that my children's teachers can not provide a comprehensive set of materials at the beginning of the year. (What have they been doing all Summer?) When there is no "text book" there are few means for the child to advance or review. When the "text book" is so fractured how can the child know what is missing? How can a parent help in such chaos? This really is no way to provide an education.

Dimensions from photographs with perspective

I needed to calculate the dimensions of some historical buildings for which I only had photographs. A WAG is acceptable as I am only making rough models of the buildings. However, I did want to know how to do it with more accuracy and so looked around for an answer. SketchUp has a facility to do this and it is remarkably easy to use. Unfortunately, the rest of SketchUp is not as it is a technical tool that expects a trained user. So I kept looking around and finally found a clear explanation of the algorithm to use.

The key to understanding the algorithm is that you make right angled triangles in a plane perpendicular to a known height. For the rest of the explanation I am going to quote the author and present his diagram:

"Starting from the corner C of the building, draw a horizontal line on the image plane. This line represents a horizontal line in space, parallel to the image plane and at the same distance (and so the same length scale) as the vertical edge of the building above C, so you can measure lengths along it. It intersects the line AB, along the other side of the building, at B. (B is not necessarily the opposite corner of the building; this particular perspective view just happens to have the corners drawn about the same distance from the central corner A.) Now triangle ABC, in space, is a right triangle (assuming the corner A of the building is a right angle). You know the length BC of the hypotenuse (by measuring with a ruler calibrated to the vertical edge C, as I've shown with the green 45-45-90 triangle--just coincidentally, this is about the same height as the building for this drawing) and the length AC of one leg, so you can find the true length AB of the other leg by AB2=BC2-AC2.

"All this assumes that your camera isn't imposing too much distortion on the image. It would probably be a good idea to test this (take a picture of an object of known dimensions at similar lens zoom settings and with similar perspective) to see if this provides accuracy sufficient for your purposes."

Found at Dimensions from photographs with perspective.

3mm awe

Over at Lead Doesn't Bleed, Mr Blanchette painted 3mm Napoleonic figures using 14 applications of color! Remember that 3mm is the distance from foot to eye. And there are hundreds of them. I am in awe.

A bookmarklet for use with Kindle "Your Highlights" page

I heard Maria Popova's Kindle highlights lament on Tim Ferris's podcast and thought I would try to solve some part of it. Below is a bookmarklet that when used while viewing the highlights page will replace the page with data from the original page and then present in a format and style suitable for copy & pasting into Evernote. It has had VERY limited testing, but perhaps you will find it useful. Note that since this code uses HTML scraping to gather the data any change Amazon.com makes to the format of the original page may adversely affect the bookmarklet's functionality.

javascript:(function(){
var O = $('<div class="books"/>');
var S;
var xs = $("#allHighlightedBooks").children();
for ( var i = 0; i < xs.length; i++ ) {
  var x = $(xs[i]);
  var c = x.attr("class");
  if ( c.indexOf("bookMain") != -1 ) {
    t = $('.title',x).text();
    a = $('.author',x).text();
    l = $('a',x).attr("href");
    b = $('<div class="book"/>').appendTo(O);
    $('<div class="title"/>').text(t).appendTo(b);
    $('<div class="author"/>').text(a).appendTo(b);
    $('<div class="link"><a href="'+l+'">'+l+'</a></div>').appendTo(b);
    S = $('<div class="selections"/>').appendTo(b);
  }
  else if ( c.indexOf("highlightRow") != -1 ) {
    h = $('.highlight',x).text();
    n = $('.noteContent',x).text();
    l = $('.linkOut',x).attr("href");
    x = $('<div class="selection"/>').appendTo(S);
    $('<div class="selection"/>').text(h).appendTo(x);
    $('<div class="note"/>').text(n).appendTo(x);
    $('<div class="link"><a href="'+l+'">'+l+'</a></div>').appendTo(x);
  }
}
$(window.document.head).html(
  '<style>' +
  'div { margin-bottom: 1ex; }' + "\n" +
  '.title { font-weight: bold; }' +
  '</style>'  
);
$(window.document.body).html(O[0].outerHTML);
})();

The following code is also at https://gist.github.com/andrewgilmartin/26fd5b2ce02a3219c96c. Any suggestions on how to better use jQuery are most welcome.

Vote NO on 4

I am opposed to the $125M URI wants for a new engineering campus. It was only a few years ago that the university wanted to cease being a state school so they would not be under state imposed regulations and their concomitant costs. And yet now they want to be a state school so that they can get $125M from the taxpayers. When URI figures out what it wants its relationship with the people of RI to be then perhaps we can consider supporting this expenditure.

Digital layout comment

A comment on Video: Why eBook Text Layout is Terrible: The problem stems from using visual design features that were designed and refined for a fixed content, and a fixed size page and/or double page spread. There are examples today that are taking the steps needed to design a new visual + dynamic language for documents. When these become more broadly adopted I don't see us missing the widows and orphans.

Disable Chrome's print dialog box

Note to self ... For Mac Chrome users that don't want Chrome's print dialog box you can disable it from the command line using

defaults write com.google.Chrome DisablePrintPreview -boolean true

When the organization can consistently repeat the success ...

When I read headlines like "Building a Trading Platform in 6 Weeks in an Organization That Would Really Rather We Didn't" I think "So what? Anyone or any small team with sufficient domain knowledge, technical skills, and tools could can do that." A one time success is only that -- a one time success. When the organization, and not a specific person or specific team, can consistently repeat the success then tell me about it.

The Danes were victorious over the Normans this Wednesday

The Danes were victorious over the Normans this Wednesday. The Normans and Danes were slated for a final confrontation

The Dane's warlord (aka Cloudbeard, Kim, &, in spirit, Leo) directed a unit of hearthguard with all favorable dice on the battleboard to take down the Norman warlord. There were tense moments of rule reading by the Normans with intent on unhinging the Dane's psyche. When rules were read and positions measured the dice were gathered -- 12 dice for hearthguard and the 5 for the warlord -- and were rolled. The warlord was hit 5 times and now needed 4 saving throws to stay on the field of battle. Only one hit was countered. The Norman warlord, majestic on his white horse let go his shield, glowered at the unbelievers, and fell to ground dead.

An Observer pattern implementation and illiterate programming

This posting is an experiment in documenting Java code using (in my case) illiterate programming. The Java source code is at The Observer Pattern and the Perl code that converted the Java code is at Simpleminded Java + Javadoc to HTML Converter.

The Observer pattern is used to create a relationship between two objects. The relationship is usually unidirectional with the observer waiting for notices from the observed. The relationships is a loose one as the observed only needs to know of the interest of the observer and the observer only needs to know of the set of and ordering of notice the observed will send. A downside of this looseness is that all notices pass through a single observer method for further dispatching.

 10 package com.andrewgilmartin.common.observation;
 11 
 12 import java.util.Set;
 13 import java.util.concurrent.BlockingQueue;
 14 import java.util.concurrent.CopyOnWriteArraySet;
 15 import java.util.concurrent.LinkedBlockingQueue;
 16 

The Observation class is only used to group all the related interfaces and classes into one file. In a typical development environment each interface and class would be in its own file.

 22 public class Observation {
 23 

The Observable is the object that is being watched. As changes are prepared and then made the observable will send consent and information notices to the observers. The notices are normally specialized classes that hold some context about the change. For example, if the notice concerns the addition of new inventory to the warehouse then the notice's class could have a method for enumerating the new inventory.

 32     public interface Observable {
 33 

If it is necessary for the observable to have approval before making a change then a consent notification is sent to the observers. Each observer will be notified and if any observer opposes the change then it must return false. The current thread will be used to notify the observers and so all the observed must wait for all observers to consent.

 42         boolean consentNotification(Object notice);
 43 

An information notification is normally sent after a change. Since the change has already occurred the notices are typically sent asynchronously by a background thread. The order of the notices is preserved, however.

 50         void informationNotification(Object notice);
 51     }
 52 

The observer is the object that is notified by the observable. There is no typed relationship beyond the Observable and Observer classes. As mentioned earlier, the notices are usually of specialized classes where each notice instance holds data relevant to the change.

 59     public interface Observer {
 60 
 61         boolean notice(Observable observable, Object notice);
 62     }
 63 

A registry is the means of establishing the relationship between the observable and the observer. This interface is distinct from Observable as it is sometimes useful to indirectly register an observer via, for example, a registrar.

 70     public interface Registry {
 71 

The order of the observers is undefined.

 75         Set<Observer> getObservers();
 76 

Adds the observer to the set of observers. Returns true if the observer was added.

 81         boolean addObserver(Observer observer);
 82 

Removes the observer from the set of observers. Returns true if the observer was among the observers and was removed.

 87         boolean deleteObserver(Observer observer);
 88     }
 89 

There is often very little difference between implementations of Observable and Registry and so this base implementation can be widely employed by any class that wants to be observed.

When extending this class make sure to document the set of notices, their consent or information role, and what is their ordering.

 98     public static class ObservableBase implements Observable, Registry {
 99 

The management of the set of observers needs to be thread-safe. The set is expected to be mostly stable over the life of the observed and so copy-on-write semantics is appropriate here.

105         private final Set<Observer> observers = new CopyOnWriteArraySet<Observer>();

Information notification notices will be sent by a background thread. A blocking queue will be used to coordinate the passing of notices from the observed to this background thread.

111         private final BlockingQueue<Object> informationNotices = new LinkedBlockingQueue<Object>();
112 
113         public ObservableBase() {

This implementation of the information notification background thread is quite simple and so uses an anonymous class for the implementation.

119             Thread informationEventsDispatcher = new Thread(new Runnable() {
120                 @Override
121                 public void run() {
122                     try {

Here the thread waits for a new notice on the queue and then sends it to each of the current observers.

127                         for (;;) {
128                             Object notice = informationNotices.take();
129                             for (Observer observer : observers) {
130                                 observer.notice(ObservableBase.this, notice);
131                             }
132                         }
133                     }
134                     catch (InterruptedException e) {
135                         // empty
136                     }
137                 }
138             });
139             informationEventsDispatcher.setDaemon(true);
140             informationEventsDispatcher.start();
141         }
142 
143         @Override
144         public boolean consentNotification(Object notice) {

As mentioned earlier, consent notifications are performed by the observed's thread. In this way, as soon as any observer opposes the change the observed must reject the change.

150             for (Observer observer : observers) {
151                 if (!observer.notice(this, notice)) {
152                     return false;
153                 }
154             }
155             return true;
156         }
157 
158         @Override
159         public void informationNotification(Object notice) {

Pass along the notice to the background thread.

163             informationNotices.add(notice);
164         }
165 
166         @Override
167         public Set<Observer> getObservers() {
168             return observers;
169         }
170 
171         @Override
172         public boolean addObserver(Observer observer) {
173             return observers.add(observer);
174         }
175 
176         @Override
177         public boolean deleteObserver(Observer observer) {
178             return observers.remove(observer);
179         }
180     }
181 

Here is a small example of using the observation interfaces and classes.

185     public static void main(String... args) throws Exception {
186 
187         class Notice {
188 
189             private int senderId;
190             private int sequenceNumber;
191 
192             public Notice(int senderId, int sequenceNumber) {
193                 this.senderId = senderId;
194                 this.sequenceNumber = sequenceNumber;
195             }
196 
197             public int getSenderId() {
198                 return senderId;
199             }
200 
201             public int getSequenceNumber() {
202                 return sequenceNumber;
203             }
204         }
205 

The Sender is an observed. All that it does it to send a stream of notices consisting of sender-id & sequence-number pairs.

210         class Sender extends ObservableBase implements Runnable {
211 
212             private int senderId;
213 
214             public Sender(int id) {
215                 this.senderId = id;
216             }
217 
218             @Override
219             public void run() {
220                 for (int sequenceNumber = 0;; sequenceNumber++) {
221                     informationNotification(new Notice(senderId, sequenceNumber));
222                     sleep(); // add some randomness to the processing.
223                 }
224             }
225         }
226 

The Receiver is an observer. All that it does is to print the notice's facts. In this example all notices are information notifications and so the notice() return value does not matter. However, as a matter of course, notice() should always return true unless it is well sure of the consequences of opposing the change.

234         class Receiver implements Observer {
235 
236             private int receiverId;
237 
238             public Receiver(int id) {
239                 this.receiverId = id;
240             }
241 
242             @Override
243             public boolean notice(Observable observable, Object notice) {
244                 if (notice instanceof Notice) {
245                     Notice n = (Notice) notice;
246                     System.out.printf("notice %d %d %d\n", receiverId, n.getSenderId(), n.getSequenceNumber());
247                     sleep(); // add some randomness to the processing.
248                 }
249                 return true;
250             }
251         }
252 

Create a few senders.

256         Sender[] senders = new Sender[5];
257         for (int i = 0; i < senders.length; i++) {
258             senders[i] = new Sender(i);
259         }
260 

Create a few receivers.

264         Receiver[] receivers = new Receiver[3];
265         for (int i = 0; i < receivers.length; i++) {
266             receivers[i] = new Receiver(i);
267         }
268 

Have each receiver observe each sender

272         for (Receiver r : receivers) {
273             for (Sender s : senders) {
274                 s.addObserver(r);
275             }
276         }
277 

Startup the senders

281         for (Sender s : senders) {
282             Thread t = new Thread(s);
283             t.setDaemon(false);
284             t.start();
285         }
286     }
287 

Add some sleep of random duration to the current thread.

291     static void sleep() {
292         try {
293             Thread.sleep(Math.round(Math.random() * 25));
294         }
295         catch (InterruptedException e) {
296             // empty
297         }
298     }
299 }

To build and run this from the command line, first compile using

303 javac -d /tmp ./src/com/andrewgilmartin/common/observation/Observation

And then run using

308 java -classpath /tmp com.andrewgilmartin.common.observation.Observation

You can show to yourself that the events are ordered by sorting the output on the receiver id and you will see that the events are in numeric order.

314 java -classpath /tmp com.andrewgilmartin.common.observation.Observation | head -20 | sort -k 2 -n -s

317 
318 // END

Her Majesty's Rugged Constabulary in preparation