<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8949810268237856091</id><updated>2012-02-15T12:11:54.656-08:00</updated><category term='Win32'/><category term='Windows Service'/><category term='Evolutionary Algorithms'/><category term='Android'/><category term='Java'/><category term='Java Native Access'/><category term='HDHomeRun'/><category term='Eclipse'/><category term='Checkers'/><category term='Blondie24'/><category term='Neural Networks'/><title type='text'>Enigma To Eureka</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-7432644519360045887</id><published>2011-11-22T19:48:00.000-08:00</published><updated>2011-11-22T19:48:50.680-08:00</updated><title type='text'>Creating a Basic Isometric Map</title><content type='html'>Last year Christian Weber wrote a &lt;a href="http://www.cw-internetdienste.de/2010/05/creating-a-basic-isometric-map/"&gt;helpful introductory article&lt;/a&gt; showing how to use CSS to layout tiles for&amp;nbsp;an &lt;a href="http://en.wikipedia.org/wiki/Video_games_with_isometric_graphics"&gt;isometric&lt;/a&gt; &lt;a href="http://www.mapeditor.org/"&gt;map&lt;/a&gt;. However,&amp;nbsp;the screen shot and &lt;a href="http://www.cw-internetdienste.de/isomap/"&gt;demo&lt;/a&gt; looked a little odd; note the black V below where you can see "underneath" a tile.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-7nTXPw74R5Y/Tsw9a-IJ08I/AAAAAAAAA3c/cJn6LHxx7nQ/s1600/cw-isometric-error.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-7nTXPw74R5Y/Tsw9a-IJ08I/AAAAAAAAA3c/cJn6LHxx7nQ/s1600/cw-isometric-error.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The problems were partly caused by placing tiles adjacent to each other when they didn't have matching sides (i.e. a side that is all grass should butt up against an all grass side of another tile). &amp;nbsp;In addition, the CSS styles for the tiles had the wrong offsets for identifying the positions of the sprites. &amp;nbsp;The code in the article compensated for the style errors with some "corrections", which of course made it more confusing.&lt;br /&gt;&lt;br /&gt;I've posted a &lt;a href="http://jsdabbler.appspot.com/home/jamessynge/isomap/random-isomap.html"&gt;corrected version here&lt;/a&gt;. &amp;nbsp;It has a table indicating the type of each tile side, allowing for the generation of a random map were each tile's neighbors are appropriate, such that there are no gaps. &amp;nbsp;For example:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-oQYbhC0rANk/Tsxswe-iwVI/AAAAAAAAA3o/1oHnjijh5t8/s1600/Isometric+Tile+Map+Test.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="177" src="http://1.bp.blogspot.com/-oQYbhC0rANk/Tsxswe-iwVI/AAAAAAAAA3o/1oHnjijh5t8/s320/Isometric+Tile+Map+Test.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-7432644519360045887?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/7432644519360045887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2011/11/creating-basic-isometric-map.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/7432644519360045887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/7432644519360045887'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2011/11/creating-basic-isometric-map.html' title='Creating a Basic Isometric Map'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-7nTXPw74R5Y/Tsw9a-IJ08I/AAAAAAAAA3c/cJn6LHxx7nQ/s72-c/cw-isometric-error.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-1070235784623444458</id><published>2011-05-08T07:37:00.000-07:00</published><updated>2011-05-08T13:16:11.242-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Service'/><category scheme='http://www.blogger.com/atom/ns#' term='Win32'/><category scheme='http://www.blogger.com/atom/ns#' term='Java Native Access'/><title type='text'>Writing a Windows Service in Java</title><content type='html'>&lt;style type="text/css"&gt;tt, .jms-inline-code {  font-family:"Courier New", Courier, monospace;  font-size:1em;}&lt;/style&gt;&lt;br /&gt;I've got a couple of Java programs that I want to leave running permanently on my laptop, so I set about creating a Windows Service. I investigated several of the alternatives (&lt;a href="http://wrapper.tanukisoftware.com/"&gt;Java Service Wrapper&lt;/a&gt;, &lt;a href="http://yajsw.sourceforge.net/"&gt;Yet Another Java Service Wrapper&lt;/a&gt;, etc.), but having recently discovered &lt;a href="http://jna.java.net/"&gt;Java Native Access&lt;/a&gt; (JNA), I decided to see if I could produce a fairly lightweight solution.&lt;br /&gt;&lt;br /&gt;JNA (and &lt;a href="http://sourceware.org/libffi/"&gt;libffi&lt;/a&gt; on which it depends) provides a means to dynamically create a bridge between Java and native libraries, a feature I've been wanting for years. I'd used JNI in the past, but I find it rather brittle. I've been pleasantly surprised to find that even when I made various mistakes with JNA, the JVM didn't crash; instead, JNA threw relatively meaningful exceptions, such as when it was unable to bridge the gap between a call from Windows to a Java method I wrote to accept that call (i.e. the argument types I used weren't appropriate). For example, the Windows Service API requires the service to implement a &lt;a href="http://msdn.microsoft.com/en-us/library/ms685138(v=VS.85).aspx"&gt;&lt;tt&gt;ServiceMain&lt;/tt&gt;&lt;/a&gt;  function which will be called by Windows:&lt;br /&gt;&lt;pre class="brush: java"&gt;VOID WINAPI ServiceMain(&lt;br /&gt;  __in DWORD dwArgc,&lt;br /&gt;  __in LPTSTR *lpszArgv&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;That lpszArgv is a pointer to an array of pointers to strings that will be passed to the ServiceMain function. I wanted to define a type, ReceiveStringArray, extending Pointer, as the type of lpszArgv in Java. Unfortunately, JNA could not bridge the gap from the native arguments to ReceiveStringArray, so I had to fallback to using JNA's Pointer as its type, and fortunately Pointer has a method, getStringArray, that handles exactly the translation needed here.&lt;br /&gt;&lt;pre class="brush: java"&gt;interface SERVICE_MAIN_FUNCTION extends StdCallCallback {&lt;br /&gt;  /**&lt;br /&gt;   * ServiceMain is the main method of the service. It should return only&lt;br /&gt;   * once the service is stopped.&lt;br /&gt;   * &lt;br /&gt;   * @param dwArgc&lt;br /&gt;   * @param argv A pointer to an array (of length dwArgc)&lt;br /&gt;   *             of pointers to strings.&lt;br /&gt;   */&lt;br /&gt;  void ServiceMain(int dwArgc, Pointer argv);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;It may be that I was missing some appropriate constructor in ReceiveStringArray, or that a JNA TypeMapper was needed to handle initializing a ReceiveStringArray in this situation.&lt;br /&gt;&lt;br /&gt;Another interesting challenge I had was that the first of my callback functions, &lt;tt&gt;ServiceMain&lt;/tt&gt;, was being called at the expected time, but it was also being called when I expected a different callback function to be called instead. I'm not certain, but I think this is because JNA doesn't really care about the name of the method in the interface; there must be a single method, and that is the one that will be called. I had created two interfaces, but only a single class implementing them both. I suspected that I needed to have a separate class (or instance?) to receive each type of callback.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;tt style="font-size: large;"&gt;StartServiceCtrlDispatcher&lt;/tt&gt;&lt;/b&gt;&lt;br /&gt;A typical Windows Service is basically just a program that runs in the background, with no direct interaction with the user, with a few extra required interactions with Windows. When the program is started it must call &lt;tt&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms686324(v=VS.85).aspx"&gt;StartServiceCtrlDispatcher&lt;/a&gt;&lt;/tt&gt;, passing in a table of services to be started (typically just one). The dispatcher starts another thread to run &lt;tt&gt;ServiceMain&lt;/tt&gt;, then it dispatches various Windows events to the service (e.g. when Windows is shutting down), and returns once the service stops.&lt;br /&gt;&lt;pre class="brush: java"&gt;import com.sun.jna.Native;&lt;br /&gt;import com.sun.jna.Structure;&lt;br /&gt;import com.sun.jna.platform.win32.Advapi32;&lt;br /&gt;import com.sun.jna.win32.W32APIOptions;&lt;br /&gt;&lt;br /&gt;public interface ExtendedAdvapi32 extends Advapi32 {&lt;br /&gt;  ExtendedAdvapi32 INSTANCE = (ExtendedAdvapi32) Native.loadLibrary(&lt;br /&gt;      "Advapi32", ExtendedAdvapi32.class, W32APIOptions.UNICODE_OPTIONS);&lt;br /&gt;  class SERVICE_TABLE_ENTRY extends Structure {&lt;br /&gt;    public String serviceName;&lt;br /&gt;    public SERVICE_MAIN_FUNCTION serviceProc;&lt;br /&gt;  }&lt;br /&gt;  boolean StartServiceCtrlDispatcher(SERVICE_TABLE_ENTRY[] lpServiceTable);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;The API doesn't include a length parameter to tell the dispatcher how many services are implemented by the program. Instead, the last entry in the table must have NULL pointers. Therefore, while the program doesn't need (at this point) the name of the service it is implementing, the field must not be NULL. Instead, set it to an empty string. For example:&lt;/div&gt;&lt;pre class="brush: java"&gt;ExtendedAdvapi32.SERVICE_TABLE_ENTRY entry =&lt;br /&gt;    new ExtendedAdvapi32.SERVICE_TABLE_ENTRY();&lt;br /&gt;entry.serviceName = "";&lt;br /&gt;entry.serviceProc = someServiceMainFunction;&lt;br /&gt;ExtendedAdvapi32.SERVICE_TABLE_ENTRY[] serviceTable =&lt;br /&gt;    (SERVICE_TABLE_ENTRY[]) entry.toArray(2);&lt;br /&gt;boolean result =&lt;br /&gt;    ExtendedAdvapi32.INSTANCE.StartServiceCtrlDispatcher(serviceTable);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;tt style="font-size: large;"&gt;ServiceMain&lt;/tt&gt;&lt;/b&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;The &lt;tt&gt;ServiceMain&lt;/tt&gt; callback function is invoked on another thread from the main thread, and shouldn't return until the service stops (usually when Windows is shutting down, but it can also be stopped and started via a control panel). The function is passed an array of strings (as an argc and argv, just like a C program's main). The first string in the array is the name of the service. The following elements of the array are the "Start Parameters". These can be set in the service's Properties dialog box:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center; margin-top: 0.5em;"&gt;&lt;a href="http://3.bp.blogspot.com/-AcGlEVfLFK4/TcVP-S3Cv-I/AAAAAAAAApI/wXMUeUI0dXw/s1600/windows-service-start-parameters.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-AcGlEVfLFK4/TcVP-S3Cv-I/AAAAAAAAApI/wXMUeUI0dXw/s1600/windows-service-start-parameters.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;tt&gt;ServiceMain&lt;/tt&gt; needs to call &lt;tt&gt;RegisterServiceCtrlHandlerEx&lt;/tt&gt; to provide the service control dispatcher with a function to be invoked when Windows notifies the service of events (e.g. when Windows is shutting down, a user logs in or out, or there is a change in connected hardware).&lt;br /&gt;&lt;pre class="brush: java"&gt;public interface ExtendedAdvapi32 extends Advapi32 {&lt;br /&gt;  interface HandlerEx extends StdCallCallback {&lt;br /&gt;    int serviceControlHandler(int serviceControlCode, int eventType,&lt;br /&gt;                              Pointer eventData, Pointer context);&lt;br /&gt;  }&lt;br /&gt;  class SERVICE_STATUS_HANDLE extends HANDLE {&lt;br /&gt;    public SERVICE_STATUS_HANDLE() { }&lt;br /&gt;    public SERVICE_STATUS_HANDLE(Pointer p) { super(p); }&lt;br /&gt;  }&lt;br /&gt;  SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerEx(&lt;br /&gt;      String serviceName, HandlerEx handler, Object context);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Next, &lt;tt&gt;ServiceMain&lt;/tt&gt; must call &lt;a href="http://msdn.microsoft.com/en-us/library/ms686241(v=VS.85).aspx"&gt;&lt;tt&gt;SetServiceStatus&lt;/tt&gt;&lt;/a&gt; to inform Windows that the service running, and the types of event notifications the service wants to receive.&lt;br /&gt;&lt;pre class="brush: java"&gt;public interface ExtendedAdvapi32 extends Advapi32 {&lt;br /&gt;  static final int SERVICE_WIN32_OWN_PROCESS = 0x00000010;&lt;br /&gt;  class SERVICE_STATUS extends Structure {&lt;br /&gt;    public int serviceType = SERVICE_WIN32_OWN_PROCESS;&lt;br /&gt;    public int currentState = 0;&lt;br /&gt;    public int controlsAccepted = 0;&lt;br /&gt;    public int win32ExitCode = W32Errors.NO_ERROR;&lt;br /&gt;    public int serviceSpecificExitCode = 0;&lt;br /&gt;    public int checkPoint = 0;&lt;br /&gt;    public int waitHint = 0;&lt;br /&gt;  }&lt;br /&gt;  boolean SetServiceStatus(SERVICE_STATUS_HANDLE serviceStatusHandle,&lt;br /&gt;                           SERVICE_STATUS serviceStatus);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;For example:&lt;/div&gt;&lt;pre class="brush: java"&gt;public interface ExtendedAdvapi32 extends Advapi32 {&lt;br /&gt;  static final int SERVICE_RUNNING = 0x00000004;&lt;br /&gt;  static final int SERVICE_ACCEPT_SHUTDOWN = 0x00000004;&lt;br /&gt;  static final int SERVICE_ACCEPT_STOP = 0x00000001;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;SERVICE_STATUS serviceStatus = new SERVICE_STATUS();&lt;br /&gt;serviceStatus.currentState = ExtendedAdvapi32.SERVICE_RUNNING;&lt;br /&gt;serviceStatus.controlsAccepted = (&lt;br /&gt;    ExtendedAdvapi32.SERVICE_ACCEPT_STOP |&lt;br /&gt;    ExtendedAdvapi32.SERVICE_ACCEPT_SHUTDOWN);&lt;br /&gt;ExtendedAdvapi32.INSTANCE.SetServiceStatus(serviceStatusHandle,&lt;br /&gt;                                           serviceStatus);&lt;br /&gt;&lt;/pre&gt;At this point the service can do its job, but it must also have some way to be notified that it is time to stop (e.g. via a flag shared between the &lt;tt&gt;ServiceMain&lt;/tt&gt; thread and the service control handler). When &lt;tt&gt;ServiceMain&lt;/tt&gt; learns that it needs to stop, it must tell Windows that it has stopped before returning.&lt;br /&gt;&lt;pre class="brush: java"&gt;public interface ExtendedAdvapi32 extends Advapi32 {&lt;br /&gt;  static final int SERVICE_STOPPED = 0x00000001;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;SERVICE_STATUS serviceStatus = new SERVICE_STATUS();&lt;br /&gt;serviceStatus.currentState = ExtendedAdvapi32.SERVICE_STOPPED;&lt;br /&gt;serviceStatus.controlsAccepted = 0; // Accept no more notifications.&lt;br /&gt;ExtendedAdvapi32.INSTANCE.SetServiceStatus(serviceStatusHandle,&lt;br /&gt;                                           serviceStatus);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Service Control Handler (&lt;tt&gt;HandlerEx&lt;/tt&gt;)&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;The service control dispatcher calls the service's control handler when the requested events occur. To support just shutdown and stop events, this suffices:&lt;br /&gt;&lt;pre class="brush: java"&gt;public interface ExtendedAdvapi32 extends Advapi32 {&lt;br /&gt;  static final int SERVICE_CONTROL_SHUTDOWN = 0x00000005;&lt;br /&gt;  static final int SERVICE_CONTROL_STOP = 0x00000001;&lt;br /&gt;&lt;br /&gt;  // Must return NO_ERROR for this, not ERROR_CALL_NOT_IMPLEMENTED.&lt;br /&gt;  static final int SERVICE_CONTROL_INTERROGATE = 0x00000004;    &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public int serviceControlHandler(int serviceControlCode, int eventType,&lt;br /&gt;                                   Pointer eventData, Pointer context) {&lt;br /&gt;  switch (serviceControlCode) {&lt;br /&gt;  case ExtendedAdvapi32.SERVICE_CONTROL_INTERROGATE:&lt;br /&gt;    return W32Errors.NO_ERROR;&lt;br /&gt;  case ExtendedAdvapi32.SERVICE_CONTROL_SHUTDOWN:&lt;br /&gt;  case ExtendedAdvapi32.SERVICE_CONTROL_STOP:&lt;br /&gt;    // TODO Signal ServiceMain to stop.&lt;br /&gt;    return W32Errors.NO_ERROR;&lt;br /&gt;  default:&lt;br /&gt;    return W32Errors.ERROR_CALL_NOT_IMPLEMENTED;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Encapsulating the Windows API&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;To avoid polluting the 'pure' Java with all of the above, I defined the following simple interface that my services would implement (which I can use on other operating systems):&lt;br /&gt;&lt;pre class="brush: java"&gt;public interface ISimpleService {&lt;br /&gt;  int run(String[] args);&lt;br /&gt;  void stop();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The return value from run could (in a slightly more complicated solution) be used to set the &lt;tt&gt;SERVICE_STATUS.serviceSpecificExitCode&lt;/tt&gt; field.&lt;br /&gt;&lt;br /&gt;These two classes are used to invoke the methods of &lt;tt&gt;ISimpleService&lt;/tt&gt;:&lt;br /&gt;&lt;pre class="brush: java"&gt;class ServiceControlHandler implements HandlerEx {&lt;br /&gt;  private final ISimpleService service;&lt;br /&gt;  public ServiceControlHandler(ISimpleService service) {&lt;br /&gt;    this.service = service;&lt;br /&gt;  }&lt;br /&gt;  public int serviceControlHandler(int serviceControlCode, int eventType,&lt;br /&gt;                                   Pointer eventData, Pointer context) {&lt;br /&gt;    switch (serviceControlCode) {&lt;br /&gt;    case ExtendedAdvapi32.SERVICE_CONTROL_INTERROGATE:&lt;br /&gt;      return W32Errors.NO_ERROR;&lt;br /&gt;    case ExtendedAdvapi32.SERVICE_CONTROL_STOP:&lt;br /&gt;      service.stop();&lt;br /&gt;      return W32Errors.NO_ERROR;&lt;br /&gt;    default:&lt;br /&gt;      return W32Errors.ERROR_CALL_NOT_IMPLEMENTED;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class SimpleServiceMain implements SERVICE_MAIN_FUNCTION {&lt;br /&gt;  private final ISimpleService simpleService;&lt;br /&gt;  private final SimpleServiceControlHandler handler;&lt;br /&gt;  private SERVICE_STATUS_HANDLE serviceStatusHandle;&lt;br /&gt;  public SimpleServiceMain(ISimpleService simpleService,&lt;br /&gt;                           SimpleServiceControlHandler handler) {&lt;br /&gt;    this.simpleService = simpleService;&lt;br /&gt;    this.handler = handler;&lt;br /&gt;  }&lt;br /&gt;  public void ServiceMain(int argc, Pointer argv) {&lt;br /&gt;    if (argc &amp;lt; 1 || argv == null) {&lt;br /&gt;      // Missing the service name.&lt;br /&gt;      return;&lt;br /&gt;    }&lt;br /&gt;    try {&lt;br /&gt;      String[] args = argv.getStringArray(0, argc, true);&lt;br /&gt;      String serviceName = args[0];&lt;br /&gt;      String[] startParameters = Arrays.copyOfRange(args, 1, args.length);&lt;br /&gt;      serviceStatusHandle =&lt;br /&gt;          ExtendedAdvapi32.INSTANCE.RegisterServiceCtrlHandlerEx(&lt;br /&gt;              serviceName, handler, null);&lt;br /&gt;      setServiceStatus(ExtendedAdvapi32.SERVICE_RUNNING,&lt;br /&gt;          ExtendedAdvapi32.SERVICE_ACCEPT_STOP |&lt;br /&gt;          ExtendedAdvapi32.SERVICE_ACCEPT_SHUTDOWN);&lt;br /&gt;      simpleService.run(startParameters);&lt;br /&gt;    } finally {&lt;br /&gt;      setServiceStatus(ExtendedAdvapi32.SERVICE_STOPPED, 0);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  private void setServiceStatus(int currentState, int controlsAccepted) {&lt;br /&gt;    SERVICE_STATUS serviceStatus = new SERVICE_STATUS();&lt;br /&gt;    serviceStatus.currentState = currentState;&lt;br /&gt;    serviceStatus.controlsAccepted = controlsAccepted;&lt;br /&gt;    ExtendedAdvapi32.INSTANCE.SetServiceStatus(&lt;br /&gt;        serviceStatusHandle, serviceStatus);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;And a function to create instances and start the service control dispatcher:&lt;br /&gt;&lt;pre class="brush: java"&gt;public static void runSimpleService(ISimpleService service) {&lt;br /&gt;  SimpleServiceControlHandler handler =&lt;br /&gt;      new SimpleServiceControlHandler(service);&lt;br /&gt;  SimpleServiceMain serviceMain =&lt;br /&gt;      new SimpleServiceMain(service, handler);&lt;br /&gt;  SERVICE_TABLE_ENTRY entry = new SERVICE_TABLE_ENTRY();&lt;br /&gt;  entry.serviceName = "";&lt;br /&gt;  entry.serviceProc = serviceMain;&lt;br /&gt;  SERVICE_TABLE_ENTRY[] serviceTable =&lt;br /&gt;      (SERVICE_TABLE_ENTRY[]) entry.toArray(2);&lt;br /&gt;  ExtendedAdvapi32.INSTANCE.StartServiceCtrlDispatcher(serviceTable);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;Example Service&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Here is a trivial service that just waits to be stopped.&lt;br /&gt;&lt;pre class="brush: java"&gt;public class WindowsServiceHandlerExample implements ISimpleService {&lt;br /&gt;  private final CountDownLatch latch = new CountDownLatch(1);&lt;br /&gt;  public int run(String[] args) {&lt;br /&gt;    try {&lt;br /&gt;      latch.await();&lt;br /&gt;    } catch (InterruptedException e) {&lt;br /&gt;    }&lt;br /&gt;    return 0;&lt;br /&gt;  }&lt;br /&gt;  public void stop() {&lt;br /&gt;    latch.countDown();&lt;br /&gt;  }&lt;br /&gt;  public static void main(String[] args) {&lt;br /&gt;    WindowsServiceUtil.runSimpleService(new WindowsServiceHandlerExample());&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-1070235784623444458?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/1070235784623444458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2011/05/writing-windows-service-in-java.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/1070235784623444458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/1070235784623444458'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2011/05/writing-windows-service-in-java.html' title='Writing a Windows Service in Java'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-AcGlEVfLFK4/TcVP-S3Cv-I/AAAAAAAAApI/wXMUeUI0dXw/s72-c/windows-service-start-parameters.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-8369702285056161641</id><published>2011-02-26T12:54:00.000-08:00</published><updated>2011-02-26T12:54:14.489-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Distributing Work</title><content type='html'>During November and December of last year I developed my checkers program to the point where I could run all three of the experiments conducted by Fogel and Chellapilla. &amp;nbsp;The longest ran for 5 days on my 2 processor laptop, which indicates that it'll take months to run some of the experiments I have in mind.&lt;br /&gt;&lt;br /&gt;Since I'm doing this exercise for fun, and I like building "systems", I decided to make a system for distributing work (games to be played) to other machines in the house. &amp;nbsp;I've developed a somewhat complicated Java web app (using embedded Jetty) that manages a jar repository and runs (in subprocesses) Java programs whose descriptions are uploaded. &amp;nbsp;The description consists of jar names and jar hashes (to avoid running the wrong version of a jar as I'm developing), a main class name, and command line. &amp;nbsp;The Java program is provided with a work area in the file system, to which the remote client can upload any necessary files prior to starting the program, and from which the remote client can download any files after the program is done, including files containing the output of the stdout and stderr streams.&lt;br /&gt;&lt;br /&gt;I say "somewhat complicated" because I didn't make the decision to use embedded Jetty until late in the process, and if I'd made it earlier, I would have used more of Jetty's facilities to handle the file management.&lt;br /&gt;&lt;br /&gt;To simplify creating the description of a Java program, I created a mechanism for walking the current process's classpath, creating jars for unpacked entries (e.g. the bin folders of my Eclipse projects), and uploading them to the various servers.&lt;br /&gt;&lt;br /&gt;Next up I'm working on how to transfer units of work from the main program to the workers, and how to get the responses back. &amp;nbsp;My current plan is to have the main program run an embedded web server (Jetty) with a servlet that a worker will contact to get a unit of work (e.g. two checkers players to compete), and will then re-contact with the result of the unit of work (e.g. the game outcome).&lt;br /&gt;&lt;br /&gt;This mechanism is certainly sufficient to the task, but feels a bit awkward. &amp;nbsp;I think I'd like some variant of a ThreadPoolExecutor that supports distributed threads, but I've not located nor invented such a beast. &amp;nbsp;Sigh.&lt;br /&gt;&lt;br /&gt;More later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-8369702285056161641?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/8369702285056161641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2011/02/distributing-work.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/8369702285056161641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/8369702285056161641'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2011/02/distributing-work.html' title='Distributing Work'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-1613809792392295657</id><published>2010-12-29T06:15:00.000-08:00</published><updated>2010-12-29T06:15:25.714-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blondie24'/><category scheme='http://www.blogger.com/atom/ns#' term='Checkers'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Yes, Virginia, Testing is Important!</title><content type='html'>In my zeal to optimize my &lt;a href="http://enigma2eureka.blogspot.com/2010/12/evaluating-checker-board-with-feed.html"&gt;checkers playing program&lt;/a&gt;, I included a number of optimizations in the search algorithm: minimax with alpha-beta pruning, plus a memory of previous partial search trees to assist in ordering of future searches, and to skip evaluations when the results are known. &amp;nbsp;Too many optimizations, as it happens.&lt;br /&gt;&lt;br /&gt;I wrote quite a few JUnit tests for the basic checkers board manipulation code, but wasn't sure how to go about testing the search algorithm. I wrote some very basic tests that the pruning was happening as expected, but left it at that.&lt;br /&gt;&lt;br /&gt;I then wrote a system for evolving the neural networks, and repeated the evolution experiments described by Fogel and Chellapilla. Again, I wasn't quite sure how to evaluate the results, as I'm not yet ready to play hundreds of games online using the best evolved network as my evaluation function.&lt;br /&gt;&lt;br /&gt;So, I studied the last generation's networks and the games they played, and noticed that they'd all played the same first move... and the same first reply... and the same next reply! The first&amp;nbsp;three&amp;nbsp;moves were all the same. &amp;nbsp;Wow! Did they all stumble upon the best opening moves? &amp;nbsp;Or perhaps all of the surviving networks were descended from a relatively recent network that made that choice?&lt;br /&gt;&lt;br /&gt;I decided to confirm that initial generation of networks was much more random in its play. &amp;nbsp;Unfortunately, upon reviewing their games, I found they too played the same first three moves. &amp;nbsp;Sigh. &amp;nbsp;Back to the drawing board.&lt;br /&gt;&lt;br /&gt;To track this down, I tried shuffling the legal move choices presented to the search algorithm, but that made no difference. &amp;nbsp;Next, I implemented minimax and compared its choices to those of my enhanced alpha-beta search. As you might expect, they didn't agree. &amp;nbsp;So, I implemented a basic alpha-beta search, which did agree with minimax. &amp;nbsp;In the course of debugging, I found several mistakes in the over optimized alpha-beta implementation, and I don't think I've found them all. &amp;nbsp;Fortunately, testing will help me figure out when I've got it wrong, and hopefully the next 1000+ generations of evolution will be more fruitful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-1613809792392295657?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/1613809792392295657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2010/12/yes-virginia-testing-is-important.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/1613809792392295657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/1613809792392295657'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2010/12/yes-virginia-testing-is-important.html' title='Yes, Virginia, Testing is Important!'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-4804664199511364810</id><published>2010-12-04T17:49:00.000-08:00</published><updated>2010-12-26T17:13:08.704-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blondie24'/><category scheme='http://www.blogger.com/atom/ns#' term='Checkers'/><category scheme='http://www.blogger.com/atom/ns#' term='Evolutionary Algorithms'/><category scheme='http://www.blogger.com/atom/ns#' term='Neural Networks'/><title type='text'>Evaluating a Checker Board with a Feed Forward Neural Network</title><content type='html'>With two-player zero-sum games such as checkers and chess, it is common to build computer players based on the idea of searching&amp;nbsp;the&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Game_tree"&gt;game tree&lt;/a&gt;&amp;nbsp;to select moves&amp;nbsp;using some variant of&amp;nbsp;&amp;nbsp;the&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Minimax"&gt;minimax&lt;/a&gt;&amp;nbsp;search algorithm and an evaluation function. &amp;nbsp;The evaluation function&amp;nbsp;takes a game board as input and returns a numeric score as output, where the score is highest when the board is a win for the player, and the score is lowest when the board is a loss for the player. &amp;nbsp;For checkers, an extremely simple example of an evaluation function just adds up the number of pieces the player has, and subtracts the number of pieces the opponent has.&lt;br /&gt;&lt;br /&gt;When using a neural network to evaluate a checkers board, we need some representation of the&amp;nbsp;checkers board and the pieces on it. &amp;nbsp;Fogel and Chellapilla chose to map the board to an array of 32 floating point numbers, where each entry had one of five values:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;+K &amp;nbsp; Player's King&lt;/li&gt;&lt;li&gt;+1 &amp;nbsp; &amp;nbsp;Player's Man&lt;/li&gt;&lt;li&gt;0 &amp;nbsp; &amp;nbsp; &amp;nbsp;Empty&lt;/li&gt;&lt;li&gt;-1 &amp;nbsp; &amp;nbsp; Opponent's Man&lt;/li&gt;&lt;li&gt;-K &amp;nbsp; &amp;nbsp;Opponent's King&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;K was an evolvable value, initialized to 2.0.&lt;br /&gt;&lt;br /&gt;In addition to the above, in their second and third experiments, they computed a value directly from the inputs (i.e. without weights): they summed the 32 floating point inputs, to come up with a value that reflects the piece differential between the two players.&lt;br /&gt;&lt;br /&gt;We can imagine other mappings. &amp;nbsp;For example, we might have several binary inputs per square, such as:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;3 bits: black, white, king; at&amp;nbsp;most one of black or white would be set, and king is only set if one of the other two is set.&lt;/li&gt;&lt;li&gt;4 bits: empty, black, white, king; at&amp;nbsp;most one of empty, black or white would be set, and king is only set if black or white is set.&lt;/li&gt;&lt;li&gt;4 bits: black king, black, white, white king; at most one would be set at a time.&lt;/li&gt;&lt;li&gt;5 bits:&amp;nbsp;black king, black, empty, white, white king; exactly&amp;nbsp;one would be set at a time.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Fogel and Chellapilla chose a search depth of 4 &lt;a href="http://en.wikipedia.org/wiki/Ply_(game_theory)"&gt;ply&lt;/a&gt;&amp;nbsp;(2 moves by each player), but extended the depth whenever a &amp;nbsp;move by a player was "forced". &amp;nbsp;Unfortunately I found their description of how this was handled a bit vague:&lt;br /&gt;&lt;blockquote&gt;In addition, when forced moves were involved, the search depth was extended (let f be the number of forced moves) because in these&amp;nbsp;situations the player has no real decision to make. The ply depth was&amp;nbsp;extended by steps of two, up to the smallest even number that was&amp;nbsp;greater than or equal to the number of forced moves f that occurred&amp;nbsp;along that branch. If the extended ply search produced more forced&amp;nbsp;moves then the ply was once again increased in a similar fashion.&amp;nbsp;Furthermore, if the final board position was left in an "active" state,&amp;nbsp;where the player has a forced jump, the depth was once again&amp;nbsp;incremented by two ply. Maintaining an even depth along each branch of&amp;nbsp;the search tree ensured that the boards were evaluated after the&amp;nbsp;opponent had an opportunity to respond to the player's move.&lt;/blockquote&gt;It wasn't clear to me whether this test is performed only on the moves of the player, or also on the moves of the opponent. &amp;nbsp;Furthermore, it wasn't clear what the definition of "forced move" was. &amp;nbsp;Did it mean that the player to move had only jumps to choose among (i.e. possibly more than one); or did it mean that the player to move had only a single move that was possible, whether it was a simple move or a jump; or did it mean that the player&amp;nbsp;to move had only a single jump available.&lt;br /&gt;&lt;br /&gt;My best guess is&amp;nbsp;that whenever the player, and not the opponent, had only jumps available&amp;nbsp;(whether they had a choice of jumps or not), the search depth on that branch of the game tree was increased by 2 ply.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;UPDATE 2010-12-09: Dr. Fogel was kind enough to respond to my questions about forced jumps, and he recalls that this meant the player whose choice it was had only a single move, and thus had no real choice. &amp;nbsp;This applied for either player in the game tree, and it didn't matter whether the move was a simple move or was a jump.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-4804664199511364810?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/4804664199511364810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2010/12/evaluating-checker-board-with-feed.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/4804664199511364810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/4804664199511364810'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2010/12/evaluating-checker-board-with-feed.html' title='Evaluating a Checker Board with a Feed Forward Neural Network'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-2685141194760537826</id><published>2010-12-01T19:14:00.000-08:00</published><updated>2010-12-26T17:11:57.045-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Blondie24'/><category scheme='http://www.blogger.com/atom/ns#' term='Checkers'/><category scheme='http://www.blogger.com/atom/ns#' term='Evolutionary Algorithms'/><category scheme='http://www.blogger.com/atom/ns#' term='Neural Networks'/><title type='text'>Blondie24 Reconsidered</title><content type='html'>I discovered &lt;a href="http://www.natural-selection.com/people_dfogel.html"&gt;David Fogel's&lt;/a&gt;&amp;nbsp;"&lt;a href="http://www.amazon.com/Blondie24-Playing-Kaufmann-Artificial-Intelligence/dp/1558607838/ref=sr_1_1?ie=UTF8&amp;amp;qid=1291248417&amp;amp;sr=8-1"&gt;Blondie24: Playing at the Edge of AI&lt;/a&gt;"&amp;nbsp;in 2006 while killing time at the library waiting for my daughter. &amp;nbsp;It is a very engaging story of his effort, with colleague &lt;a href="http://research.microsoft.com/en-us/um/people/kumarc/"&gt;Kumar Chellapilla&lt;/a&gt;, to evolve an American Checkers (&lt;a href="http://en.wikipedia.org/wiki/Draughts"&gt;English Draughts&lt;/a&gt;) "player", with &lt;b&gt;no&lt;/b&gt; human expertise provided, and then to evaluate that player by competing online against (presumably) people on zone.com (now zone.msn.com).&lt;br /&gt;&lt;br /&gt;Dr. Fogel covers the history of AI in playing chess and checkers, and provides background on evolutionary algorithms and artificial neural networks. &amp;nbsp;He then covers the three network topologies they used, and the training algorithm, the key feature of which is that they created a random of population of players (really, evaluation functions), and had those players, and their offspring, compete against each other in tens of thousands of checkers games across hundreds of generations, keeping and evolving the most successful players..&lt;br /&gt;&lt;br /&gt;One of the challenges they faced was limited computing resources; I think they were doing this work around the year 2000, and that the machine they had available to (mostly) dedicate to this task was a PC with a 400MHz Pentium processor. &amp;nbsp;For their final network topology, in which their were more than 5000 weights to be adjusted, it took 6 months to run through 800 generations. &amp;nbsp;As a result, they were not able to explore the many lines of investigation that spring to mind.&lt;br /&gt;&lt;br /&gt;I'm interested in following some of those lines, and I have the&amp;nbsp;luxury of 10 more years of CPU development. &amp;nbsp;To provide a baseline, I've been working to reproduce their work, based on the information in Dr. Fogel's book, and the several papers they published together on the topic. &amp;nbsp;I'll be writing about my efforts in posts to follow this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-2685141194760537826?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/2685141194760537826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2010/12/blondie24-reconsidered.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/2685141194760537826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/2685141194760537826'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2010/12/blondie24-reconsidered.html' title='Blondie24 Reconsidered'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-2756541766406619974</id><published>2009-12-27T10:58:00.000-08:00</published><updated>2009-12-27T10:58:11.480-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><title type='text'>Android Emulator -- Please Wait</title><content type='html'>I'm trying out the Android Development Tools (Eclipse-based), and have been very frustrated at the fact that the Hello World application wouldn't run.  The emulator just sat there display the word Android (not the logo) for several minutes until I gave up:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_n9NNFvaRIMU/SzeshMdvAWI/AAAAAAAAAYY/0g7kyM-Bh8k/s1600-h/android-boot-screen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_n9NNFvaRIMU/SzeshMdvAWI/AAAAAAAAAYY/0g7kyM-Bh8k/s320/android-boot-screen.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I searched for suggestions, and it turned out that the problem was simply that I was being impatient.  The first time you run the emulator with a specific Android Virtual Device (avd), it sets up a bunch of image files, and this is apparently rather time consuming. &amp;nbsp;After a while, you see this screen (SDK 1.6) with the animated Android logo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_n9NNFvaRIMU/SzetK8zwB1I/AAAAAAAAAYg/15HlZayd8Rc/s1600-h/android-boot-screen-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_n9NNFvaRIMU/SzetK8zwB1I/AAAAAAAAAYg/15HlZayd8Rc/s320/android-boot-screen-2.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;And finally, it reaches the home screen (or your application, depending on how you launched the emulator):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_n9NNFvaRIMU/SzetzyqnrVI/AAAAAAAAAYo/J7brjOBeXRQ/s1600-h/android-home-screen.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_n9NNFvaRIMU/SzetzyqnrVI/AAAAAAAAAYo/J7brjOBeXRQ/s320/android-home-screen.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;So, apparently patience IS a virtue. :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-2756541766406619974?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/2756541766406619974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2009/12/android-emulator-please-wait.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/2756541766406619974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/2756541766406619974'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2009/12/android-emulator-please-wait.html' title='Android Emulator -- Please Wait'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_n9NNFvaRIMU/SzeshMdvAWI/AAAAAAAAAYY/0g7kyM-Bh8k/s72-c/android-boot-screen.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-3262753276628566305</id><published>2009-09-27T08:22:00.000-07:00</published><updated>2009-09-27T15:40:59.379-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>Update to Finding Your IP v4 Broadcast Address Using Java</title><content type='html'>My earlier post &lt;a href="http://enigma2eureka.blogspot.com/2009/08/finding-your-ip-v4-broadcast-address.html"&gt;Finding Your IP v4 Broadcast Address Using Java&lt;/a&gt; mentioned that you can set the property &lt;tt&gt;java.net.preferIPv4Stack&lt;/tt&gt; using &lt;tt&gt;System.setProperty()&lt;/tt&gt;.  I recently wrote a JUnit test of code that used that approach, which failed.  After some investigation I realized that Eclipse's JUnit test runner uses a socket to communicate test results back to Eclipse, and that socket had been opened long before my code was able to set the system property.&lt;br /&gt;&lt;br /&gt;So, the basic conclusion is that if you must force the use of the IPv4 stack, do so using the command-line:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;-Djava.net.preferIPv4Stack=true&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-3262753276628566305?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/3262753276628566305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2009/09/update-to-finding-your-ip-v4-broadcast.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/3262753276628566305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/3262753276628566305'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2009/09/update-to-finding-your-ip-v4-broadcast.html' title='Update to Finding Your IP v4 Broadcast Address Using Java'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-7762017263624294468</id><published>2009-08-29T07:34:00.000-07:00</published><updated>2009-08-29T08:38:00.381-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Eclipse'/><title type='text'>I'm A Ternary Expression, What's My Type?</title><content type='html'>I was rather annoyed today to find yet another difference between the Eclipse Java compiler, and the Sun Java compiler (1.5, in both cases). Today's challenge was with a ternary expression. I had code with the following structure:&lt;div&gt;&lt;/div&gt;&lt;pre class="brush:java"&gt;package dummy;&lt;br /&gt;interface Proxy {}&lt;br /&gt;&lt;br /&gt;abstract class Base {&lt;br /&gt; Base(Base owner) {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;abstract class TypedBase extends Base {&lt;br /&gt;  TypedBase(Base owner) {super(owner);}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class ObjectClass extends TypedBase implements Proxy {&lt;br /&gt;  public ObjectClass() {&lt;br /&gt;    super(null);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class SubType extends Base implements Proxy {&lt;br /&gt;  SubType(ObjectClass owner) {&lt;br /&gt;    super(owner);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class ObjectProperty extends TypedBase implements Proxy {&lt;br /&gt;  public ObjectProperty(ObjectClass objectClass, SubType optionalSubType) {&lt;br /&gt;    super(optionalSubType == null ? objectClass : optionalSubType);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;This code compiled fine with Eclipse, but not with the Sun compiler, which complained as follows:&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;pre class="brush:java"&gt;CompilerTest.java:[27,4] cannot find symbol&lt;br /&gt;symbol  : constructor TypedBase(java.lang.Object&amp;amp;dummy.Proxy&amp;amp;dummy.Base)&lt;br /&gt;location: class dummy.TypedBase&lt;br /&gt;&lt;br /&gt;CompilerTest.java:[27,4] cannot find symbol&lt;br /&gt;symbol  : constructor TypedBase(java.lang.Object&amp;amp;dummy.Proxy&amp;amp;dummy.Base)&lt;br /&gt;location: class dummy.TypedBase&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;/div&gt;It appears that Eclipse has determined the type of the ternary expression to be dummy.Base (makes sense to me), but the Sun compiler seems to have employed the Java Generics facilities which allow one to have multiple constraints on a type variable.  Reading the Java Language Specification, the Sun compiler appears to be &lt;a href="http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25"&gt;doing what the spec says&lt;/a&gt;, which is little consolation.  I found a &lt;a href="http://bugs.sun.com/view_bug.do;?bug_id=6721089"&gt;bug report&lt;/a&gt; that explains the problem in more detail, and requests that the spec for the ternary expression be fixed to avoid this problem (which I think would make the spec line up with the Eclipse compiler's behavior).&lt;br /&gt;&lt;div&gt;&lt;/div&gt;There is of course a simple fix: add a cast to the desired type, Base in this case.  I actually chose to create a helper method as shown below because I find ternary expressions problematic to debug (i.e. I prefer to have if/then/else statements, which allow me to set separate breakpoints on the branches of the if).&lt;br /&gt;&lt;div&gt;&lt;/div&gt;&lt;pre class="brush:java"&gt;class ObjectProperty extends TypedBase implements Proxy {&lt;br /&gt;  public ObjectProperty(&lt;br /&gt;      ObjectClass objectClass,&lt;br /&gt;      SubType optionalSubType) {&lt;br /&gt;    super(chooseOwner(objectClass, optionalSubType));&lt;br /&gt;  }&lt;br /&gt;  private static Base chooseOwner(&lt;br /&gt;      ObjectClass objectClass,&lt;br /&gt;      SubType optionalSubType) {&lt;br /&gt;    if (optionalSubType == null)&lt;br /&gt;      return objectClass;&lt;br /&gt;    else&lt;br /&gt;      return optionalSubType;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-7762017263624294468?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/7762017263624294468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/im-ternary-expression-whats-my-type.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/7762017263624294468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/7762017263624294468'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/im-ternary-expression-whats-my-type.html' title='I&apos;m A Ternary Expression, What&apos;s My Type?'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-6644358959685125696</id><published>2009-08-23T12:52:00.000-07:00</published><updated>2009-08-28T10:30:15.234-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HDHomeRun'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Finding Your IP v4 Broadcast Address Using Java</title><content type='html'>I was pleased when Java 1.4 added the ability to find the available network interfaces, and more recently added the ability to get details of the addresses of those interfaces (in 1.6), because these features make it easier to write "system" tools.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;As part of writing a Java interface to the HDHomeRun, I wanted to broadcast a discovery packet to my local subnet, to which the HDHomeRun would respond. At first I just hard-coded the address 192.168.0.255, which worked fine, but wasn't very portable.  In fact, I've since changed routers, which happened to change the local subnet to 192.168.1.0, with a broadcast address of 192.168.1.255.  So, I made use of the Java classes &lt;a href="http://java.sun.com/javase/6/docs/api/index.html?java/net/NetworkInterface.html"&gt;&lt;tt&gt;java.net.NetworkInterface&lt;/tt&gt;&lt;/a&gt; and &lt;a href="http://java.sun.com/javase/6/docs/api/index.html?java/net/InterfaceAddress.html"&gt;&lt;tt&gt;java.net.InterfaceAddress&lt;/tt&gt;&lt;/a&gt;, roughly as follows:&lt;br /&gt;&lt;div&gt;&lt;div style="margin-left: 2em font-family:Monospace white-space:pre;"&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;Enumeration&amp;lt;NetworkInterface&gt; interfaces =&lt;br /&gt;    NetworkInterface.getNetworkInterfaces();&lt;br /&gt;while (interfaces.hasMoreElements()) {&lt;br /&gt;  NetworkInterface networkInterface = interfaces.nextElement();&lt;br /&gt;  if (networkInterface.isLoopback())&lt;br /&gt;    continue;    // Don't want to broadcast to the loopback interface&lt;br /&gt;  for (InterfaceAddress interfaceAddress :&lt;br /&gt;           networkInterface.getInterfaceAddresses()) {&lt;br /&gt;    InetAddress broadcast = interfaceAddress.getBroadcast();&lt;br /&gt;    if (broadcast == null)&lt;br /&gt;      continue;&lt;br /&gt;    // Use the address&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I was surprised when I ran my test of this code to discover that the broadcast address reported was 255.255.255.255.  Something was clearly wrong.  It turns out that the JRE will use the IPv6 stack if it is available, else will use IPv4. When using an IPv6 stack, InterfaceAddress never has an accurate IPv4 broadcast address. Sigh.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;/div&gt;Fortunately, there is a Java system property that directs the JRE to use the IPv4 stack:&lt;br /&gt;&lt;tt&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;java.net.preferIPv4Stack&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;This can be set on the command line (i.e. &lt;tt&gt;-Djava.net.preferIPv4Stack=true&lt;/tt&gt;), or it can be set prior to calling &lt;a href="http://java.sun.com/javase/6/docs/api/java/net/NetworkInterface.html#getNetworkInterfaces()"&gt;&lt;tt&gt;NetworkInterface.getNetworkInterfaces()&lt;/tt&gt;&lt;/a&gt;. Changing the system property &lt;b&gt;after&lt;/b&gt;&amp;nbsp;the first call to &lt;tt&gt;getNetworkInterfaces()&lt;/tt&gt; has no effect (i.e. it is too late; it appears that the choice of network stacks is locked at that point). &amp;nbsp;I suspect that any call that loads the networking stack will lock the choice.&lt;/div&gt;&lt;br /&gt;I found the pointer to the Java system property in a &lt;a href="http://forums.sun.com/thread.jspa?threadID=5277744"&gt;Sun Forums posting by Ivan Jozsef Balazs&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-6644358959685125696?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/6644358959685125696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/finding-your-ip-v4-broadcast-address.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/6644358959685125696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/6644358959685125696'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/finding-your-ip-v4-broadcast-address.html' title='Finding Your IP v4 Broadcast Address Using Java'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-1242887670692794105</id><published>2009-08-22T10:07:00.001-07:00</published><updated>2009-08-29T10:20:08.648-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HDHomeRun'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>HDHomeRun Packet Structure</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: 'Times New Roman'; "&gt;&lt;div style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 3px; padding-right: 3px; padding-bottom: 3px; padding-left: 3px; width: auto; font: normal normal normal 100%/normal Georgia, serif; text-align: left; "&gt;&lt;div&gt;The HDHomeRun has 3 types of RPC:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Discover, which locates HDHomeRun devices on the network&lt;/li&gt;&lt;li&gt;Get/Set, which read and write variables&lt;/li&gt;&lt;li&gt;Upgrade, used to upgrade the firmware (I've only done this using the provided tool)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The variables are used to tune one of the two tuners on the device to a particular frequency (i.e. select an &lt;a href="http://en.wikipedia.org/wiki/Transport_stream"&gt;MPEG-2 Transport Stream&lt;/a&gt; from the many that might be provided by source), to get status information (e.g. the signal strength and error count measured by each tuner), and of course to specify where the selected video data stream is to be sent.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Except for the video data stream, all packets to and from the HDHomeRun have the following structure:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Packet Type (16-bit big endian integer)&lt;/li&gt;&lt;li&gt;Payload Length in Bytes (16-bit big endian integer)&lt;/li&gt;&lt;li&gt;Payload&lt;/li&gt;&lt;li&gt;CRC (32-bit little endian integer)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;The payload of the Discover and Get/Set packets consists of a sequence of &lt;a href="http://en.wikipedia.org/wiki/Type-length-value"&gt;TLV&lt;/a&gt; (Tag, Length, Value) tuples with this structure:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Tag (8-bit integer)&lt;/li&gt;&lt;li&gt;Value Length in Bytes (variable length integer, 1 or 2 bytes, described below)&lt;/li&gt;&lt;li&gt;Value&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;When the value length is 127 or less, it is just 1 byte.  But when it is 128 or greater, the first byte is the low-order 7 bits, with bit 8 (the high bit) set, and the next byte is the length shifted down by 7 bits.  The value length won't be larger than 1460, because that is the maximum length of an entire packet, so we won't ever need to send more than 11 bits of length.  For those familiar with Unicode, this is vaguely reminiscent of &lt;a href="http://en.wikipedia.org/wiki/UTF-8"&gt;UTF-8&lt;/a&gt; (though UTF-8 is big endian, and supports encoding code points with more bits).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-1242887670692794105?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/1242887670692794105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/hdhomerun-packet-structure.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/1242887670692794105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/1242887670692794105'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/hdhomerun-packet-structure.html' title='HDHomeRun Packet Structure'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-2707970718893008144</id><published>2009-08-17T14:01:00.001-07:00</published><updated>2009-08-29T10:19:24.770-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HDHomeRun'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>HDHomeRun and Java</title><content type='html'>&lt;div&gt;&lt;div&gt;I've had several DVRs over the last 5 years: a Panasonic DMR-E85H, a Windows Media Center PC with Linksys Media Center Extenders, and currently a Verizon FiOS HD DVR. While I liked their basic capabilities, I've always found that there were features I wanted to add, but the devices weren't (very) open to extension.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I was thus intrigued by an unusual device, the &lt;a href="http://www.silicondust.com/products/hdhomerun_atsc"&gt;HDHomeRun&lt;/a&gt; from SiliconDust. It has two digital TV tuners, and forwards the selected video data stream(s) via Ethernet to an IP address and port. Each tuner has its own coax jack, and can be connected to either cable TV, or to a digital TV antenna (e.g. for over-the-air HDTV). The HDHomeRun could easily be a key component of a home brew DVR, and the price was low enough that I decided to buy one to experiment with.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The HDHomeRun comes with a C library and command-line program for controlling the HDHomeRun, but I prefer to write in Java, especially when it comes to multi-threaded software, which a DVR would definitely be.  Fortunately, the library source is available, along with &lt;a href="http://www.silicondust.com/hdhomerun/hdhomerun_development.pdf"&gt;a document&lt;/a&gt; explaining quite about the process of interacting with the device.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This will be the first of several posts regarding the HDHomeRun and the Java library I created to interact with it.  More soon...&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-2707970718893008144?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/2707970718893008144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/hdhomerun-and-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/2707970718893008144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/2707970718893008144'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/hdhomerun-and-java.html' title='HDHomeRun and Java'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8949810268237856091.post-3671343412852594937</id><published>2009-08-14T04:38:00.000-07:00</published><updated>2009-08-29T08:23:51.098-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>NEJUG: Career 2.0, JFugue and Log4JFugue</title><content type='html'>&lt;div&gt;The &lt;a href="http://nejug.org/"&gt;NEJUG &lt;/a&gt;(New England Java Users Group) event last night featured not one but three presentations. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The headliner was &lt;a href="http://nfjsone.com/conference/speaker/jared_richardson"&gt;Jared Richardson&lt;/a&gt; with his presentation "&lt;a href="http://www.lulu.com/content/5925115"&gt;Career 2.0: Take Control of Your Life&lt;/a&gt;".  Prior to that were two short presentations: &lt;a href="http://www.davekoelle.com/"&gt;David Koelle&lt;/a&gt; introducing &lt;a href="http://www.jfugue.org"&gt;JFugue&lt;/a&gt;, an API for generating music with little code; and &lt;a href="http://briantarbox.blogspot.com/"&gt;Brian Tarbox&lt;/a&gt; demonstrating &lt;a href="http://log4jfugue.org"&gt;Log4JFugue&lt;/a&gt;, an entertaining intersection of Log4J and JFugue.&lt;br /&gt;&lt;br /&gt;Jared had some good observations about types of workers (Jellyfish and Sharks), and some sensible advice for being proactive with your career (Learn and Share).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In Jared's parlance, a Jellyfish is someone who does what his job requires, what his boss needs, but doesn't do more than that; the career of a Jellyfish drifts on the currents of work assignments.  His best example was a friend who wouldn't learn anything new if he wasn't being paid to do it (nice work if you can get it, but you're not likely to get that often).  At the other extreme, a Shark regularly seeks out new opportunities, and learning proactively so as to be ready for those opportunities.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Grossly simplified, Jared had these recommendations:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Learn something, such as the LOTY (Language Of The Year) or the TOTY (Technology Of The Year)&lt;/li&gt;&lt;li&gt;Share what you learn: Blog, Speak, Write Articles, etc.&lt;/li&gt;&lt;li&gt;Set measurable goals: short term goals (e.g. write 1 page today) that help you take steps to meet your long term goals (write that book!)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Jared has posted a video of this presentation at &lt;a href="http://qik.com/video/1009098"&gt;http://qik.com/video/1009098&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8949810268237856091-3671343412852594937?l=enigma2eureka.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://enigma2eureka.blogspot.com/feeds/3671343412852594937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/nejug-career-20-jfugue-and-log4jfugue.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/3671343412852594937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8949810268237856091/posts/default/3671343412852594937'/><link rel='alternate' type='text/html' href='http://enigma2eureka.blogspot.com/2009/08/nejug-career-20-jfugue-and-log4jfugue.html' title='NEJUG: Career 2.0, JFugue and Log4JFugue'/><author><name>James Synge</name><uri>https://profiles.google.com/104245927791320383809</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/-zRaYcOYQQwc/AAAAAAAAAAI/AAAAAAAAAAA/hrpmxPE2qBQ/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry></feed>
