Dylan Web in 60 Seconds

This will be a series of posts about how to do web programming in Dylan. It was inspired by a version of the same thing written for Twisted Python. In Twisted, it is often the case that very little code is required to get something basic running, which was also an inspiration to create similarly simple APIs for the Dylan web infrastructure.

  1. Serving Static Content
  2. Serving Dynamic Content
  3. Static URL Routing

Generate emacs TAGS files in Dylan

In the upcoming 2020.1 release of Open Dylan the ability to export TAGS files was added. It requires the use of the interactive mode of dylan-compiler.

  1. Start the interactive compiler:
    $ dylan-compiler
  2. Open your project (assumes there is a registry file for it):
    > open my-project
  3. Build it, if it hasn’t been built:
    > build
  4. Export the TAGS file
    > export -file TAGS tags

You should now have an emacs tags file called “TAGS” in the current directory that contains tags for the Dylan code in my-project and any libraries it uses, “all the way down”.

This feature was relatively simple to add (it was written by Peter Housel in this commit) because it leverages the existing cross reference databases used by the Open Dylan IDE.

A useful trick is to define a library that uses all the libraries you think you might ever want to use, then compile that library and generate a single tags file from it. This way you aren’t limited to jumping to definitions you’re currently using in my-project.

Happy meta-dotting.

Fixing Ubuntu Unity

If you’re like me, you like to be able to see the controls that are part of the User Interfaces on your computer screen.  If you’ve recently upgraded to the Ubuntu Unity desktop you’ve realized that not everyone cares as much about this as you do.  Least of all the Unity developers.  Here are a few tips to help you restore some sanity to your Unity desktop.

  1. Scroll Bars
    Unity comes with scroll bars that hide themselves until you move the mouse over them.  This is stoopid.  To be fair, this isn’t a feature of Unity, because if you switch to a different window manager like xfce they’ll still be there.  Anyway,  do this to restore sanity:

    gsettings set org.gnome.desktop.interface ubuntu-overlay-scrollbars false

    Now log out and log back in.  Voilà!  Sanity restored!

  2. Application Menus
    Unity developers thought it would be awesome if you had no idea where the application menu was, so they moved it to the top task bar and made it invisible, unless you move the mouse over it by accident.  Nice going Unity developers!

    sudo apt-get remove indicator-appmenu

    Now log out and then back in.  Sanity restored!

  3. Task Switcher
    Naturally when you’re using the Alt-Tab task switcher you don’t give a care about being able to tell which application icon is highlighted, amiright?  Unity developers agreed!  Anyway, the easiest way I found to fix this problem (far easier than editing PNG files in gimp, thank you very much) is to log out and next to your name where you can login again is a cryptic icon.  Click it and select “Ubuntu 2D”.Sanity restored!

You’re welcome.

Static URL Routing

This is the third in a series of articles about web programming in Dylan. This example will show how URL routing works in the Dylan web server, and how to handle optional URL elements for your resources.

I will skip the library and module definitions since they’re essentially the same as in the previous examples, but they are included in the full code listing at the end.

In the Dylan web server, add-resource maps a URL to a resource. The default implementation of add-resource builds up a tree structure whose paths are defined by URL path elements and whose leaves are <resource> objects. (Idea stolen from twisted.web. I hope to add a simple regular expression based router in the future, for comparison.)

For this example we’ll use a hypothetical wiki as our web application and add three different URLs for it. First, we need a $wiki-app resource that will be the root of all wiki URLs, and specialized resource classes to provide behavior. We’ll implement page, user and group resources for the wiki:

 
define constant $wiki-app = make(<resource>);
define class <page> (<resource>) end;
define class <user> (<resource>) end;
define class <group> (<resource>) end;

Now wiki resources can be added as children of $wiki-app:

 
add-resource($wiki-app, "page/{action}/{title}/{version?}", make(<page>));
add-resource($wiki-app, "user/{action}/{name}", make(<user>));
add-resource($wiki-app, "group/{action}/{name}", make(<group>))

The URL path elements surrounded by curly braces are "path variables". Let’s decompose the first URL above: page/{action}/{title}/{version?}. The first element, "page" must be matched literally. The {action} and {title} elements are required path variables; if either is missing 404 is returned. The last element, {version?} is optional, as indicated by the ‘?’ character. (Two more path variable types that aren’t shown here are available: {v*} matches zero or more path elements and {v+} matches one or more.)

In order to define the behavior of our various resources we define methods on the respond generic function. Note that each path variable in the URL passed to add-resource corresponds to a keyword in the respond method for the resource being added. (For our purposes the behavior will be to simply display the values of all the path variables.)

 
define method respond
    (resource :: <page>, #key action, title, version)
  output("<html><body>action = %s, title = %s, version = %s</body></html>",
         action, title, version);
end;

The respond methods for <user> and <group> are similar. Notice that version may be #f but action and title will always be strings.

Lastly, we’ll connect $wiki-app to the root URL (/) and start the server:

 
define constant $server = make(<http-server>, listeners: #("0.0.0.0:8888"));
add-resource($server, "/", $wiki-app);
start-server($server);

That’s it. Run the server and click on some of these URLs to see the corresponding behavior:

Here’s the full code listing:

 
-----------library.dylan------------
Module: dylan-user
 
define library web60-static-routing
  use common-dylan;
  use koala;
end;
 
define module web60-static-routing
  use common-dylan;
  use koala;
end;
 
-----------static-routing.dylan------------
Module: web60-static-routing
 
define constant $wiki-app = make(<resource>);
 
define class <page> (<resource>) end;
define class <user> (<resource>) end;
define class <group> (<resource>) end;
 
add-resource($wiki-app, "page/{action}/{title}/{version?}", make(<page>));
add-resource($wiki-app, "user/{action}/{name}", make(<user>));
add-resource($wiki-app, "group/{action}/{name}", make(<group>));
 
define method respond
    (resource :: <page>, #key action, title, version)
  output("<html><body>action = %s, title = %s, version = %s</body></html>",
         action, title, version);
end;
 
define method respond
    (resource :: type-union(<user>, <group>), #key action, name)
  output("<html><body>action = %s, name = %s</body></html>",
         action, name);
end;
 
define constant $server = make(<http-server>, listeners: #("0.0.0.0:8888"));
add-resource($server, "/", $wiki-app);
start-server($server);

Previous: Serving Dynamic Content

Back to top

Broken shortcuts on gnome with dvorak

Let’s say you’re one of the three people who uses the dvorak keyboard layout and Gnome on Linux. (I apparently have a weakness for, how shall I say it, esoteric choices. c.f., my Dylan-related posts.) You try to use the Keyboard Preferences control panel to setup your keyboard layout switcher and suddenly notice your terminal windows keep disappearing on you. WTF?

You do some fiddling and eventually discover that even though your keyboard is nominally in dvorak layout, the keyboard shortcuts are still using qwerty layout and Control-d was really sending Control-d instead of the expected Control-e. Although some people claim this makes sense, I can only assume this was a mistake and those people are on crack. (Okay, maybe not crack…maybe they just don’t touch type, but is it really that different?)

It turns out that there’s a relatively easy solution IF you have both the “USA” and “USA Dvorak” layouts listed in your “Selected layouts”. Make sure “USA Dvorak” is listed first and “USA” is listed second. You can do this by removing the “USA” layout and re-adding it.

Intuitive, right?

As an added bonus to this solution, the keyboard switcher widget in the task bar now calls the “USA” layout “USA2” and calls the “USA Dvorak” layout “USA”.

Happy dvoraking.

Serving Dynamic Content

This is the second in a series of articles about web programming in Dylan. This example will show how to dynamically generate the contents of a web page.

First, the ever-exciting library and module definitions. In addition to common-dylan and koala (the HTTP server) we need streams for writing data to the response and date so we can show something dynamic happening:

define library web60-dynamic-content
  use common-dylan;
  use io, import: { streams };
  use koala;
  use system, import: { date };
end;

define module web60-dynamic-content
  use common-dylan;
  use date, import: { as-iso8601-string, current-date };
  use koala;
  use streams, import: { write };
end;

A web page is a resource mapped to a URL inside the web server. To create a resource we subclass <resource>:

define class <clock-page> (<resource>) end;

To make our resource do something we define a method on respond. (If we only wanted to implement the GET request method we could define a method on respond-to-get instead.)

define method respond (page :: <clock-page>, #key)
  let stream = current-response();
  let date = as-iso8601-string(current-date());
  write(stream, concatenate("<html><body>", date, "</body></html>"));
end;

current-response() returns the active <response> object. To send data back to the client we write to the current response.

let server = make(<http-server>,
                  listeners: list("0.0.0.0:8888"));
add-resource(server, "/", make(<clock-page>));
start-server(server);

In the previous example we already saw how to create and start a server, so the new bit here is using add-resource to map a URL to a <resource>. The first argument to add-resource is the URL router. (In Routes terminology it would be a "mapper".) For convenience, an <http-server> is a kind of router so we can add resources directly to the server. In a future example, I will show how to do more complex URL routing, which will explain the reason for the mysterious #key in the respond definition above.

Here’s the complete code:

---- File: library.dylan ----
Module: dylan-user

define library web60-dynamic-content
  use common-dylan;
  use io, import: { streams };
  use koala;
  use system, import: { date };
end;

define module web60-dynamic-content
  use common-dylan;
  use date, import: { as-iso8601-string, current-date };
  use koala;
  use streams, import: { write };
end;

---- File: main.dylan ----
Module: web60-dynamic-content

define class <clock-page> (<resource>)
end;

define method respond (page :: <clock-page>, #key)
  let stream = current-response();
  let date = as-iso8601-string(current-date());
  write(stream, concatenate("<html><body>", date, "</body></html>"));
end;

let server = make(<http-server>,
                  listeners: list("0.0.0.0:8888"));
add-resource(server, "/", make(<clock-page>));
start-server(server);

Run this example and point your browser at http://127.0.0.1:8888/.

Previous: Serving Static Content

Back to top

Serving Static Content

This example will show you how to use the Dylan web server (koala) to
serve static content from the file-system. First I’ll go through the
process line by line and then will show the complete code.

First, we need an HTTP server. We’ll make it listen to all interfaces
on port 8888:

let server = make(<http-server>,
                  listeners: list("0.0.0.0:8888"));

Instances of <resource> are responsible for generating HTTP
responses. To serve static content we create a
<directory-resource> whose file-system directory is /tmp and which
allows directory listings:

let resource = make(<directory-resource>,
                    directory: "/tmp",    // c:\tmp on Windows
                    allow-directory-listing?: #t);

Next we connect the resource to a specific URL on the server:

add-resource(server, "/", resource);

Last, we start the server:

start-server(server);

If you wanted to start the server in a separate thread you could say
this instead:

start-server(server, background: #t);

The entire example, including the library and module definitions,
looks like this:

---- File: library.dylan ----
Module: dylan-user

define library web60-static-content
  use common-dylan;
  use koala;
end;

define module web60-static-content
  use common-dylan;
  use koala;
end;

---- File: main.dylan ----
Module: web60-static-content

define function main ()
  let server = make(<http-server>,
                    listeners: list("0.0.0.0:8888"));
  let resource = make(<directory-resource>,
                      directory: "c:/tmp",
                      allow-directory-listing?: #t);
  add-resource(server, "/", resource);
  start-server(server);
end;

main();

Run this example and point your browser at http://127.0.0.1:8888/.

Note that serving static content is one of the things built into koala itself, so if that’s all you need to do this will accomplish the same thing:

koala --listen 0.0.0.0:8888 --directory /tmp

Millenium Leaper

In 1982-3 I wrote an arcade style game for the Apple II called Millenium Leaper and sold it to a disk magazine called Softdisk.  I didn’t think much about it again until in 2007 I was having a conversation with someone about old computer games and it occurred to me to search for references to it on the net.  To my utter surprise I found that it could be downloaded in a bundle with another game from the same period called Beer Run, and I could run it on Windows in an Apple II simulator.  I didn’t do much with it since I was involved with a fun project at work.  It came up in conversation again recently and I decided to write up my experiences developing the game, and to document the game itself.  This effort is mainly for my own satisfaction in recalling old memories, but I hope it will be of some interest to others as well.

In 1982 my dad bought an Apple II+ computer.  I was just out of high-school and had a job washing dishes while I figured out what to do with my life (although I didn’t realize that’s what was going on at the time) so I had time to burn.  My dad showed me how to do a few simple graphics tricks in Applesoft BASIC and before too long I relocated the computer from his room to mine.

Pretty quickly it became obvious that there was no way to do the types of things I was seeing in the video arcades and in some of the more advanced Apple II games of the time with Applesoft BASIC.  I had to use something that would allow me to write directly to the HI-RES video memory and I ended up getting a copy of the LISA assembler by Randy Hyde and teaching myself 6502 assembly language.  (Some time later I contributed code to that assembler  but for the life of me I can’t remember what my code did.  I received some paltry royalties for my contributions…I have to wonder if Randy was just being kind to a young kid since I’m sure he could have easily written the same thing himself.) I’m not sure if there were any C compilers available at the time for the Apple II, but I didn’t know enough to look for them if there were.

I embarked on what turned out to be an almost two-year project to learn 6502 and write a video game.  Many of the details of that process elude me.  I remember learning some basic techniques like a routine to convert hex to decimal, then experimenting endlessly to create some cool sounds on the speaker ($C030).  There was a mode in which you could display hi-res graphics on the top 3/4 of the screen and text on the bottom 1/4, and I used this to manually modify memory and see what happened to the graphic display.  For example I might store #$81 at location $4000 and see the pixel at x=7, y=0 turn green.  I played around with this enough to start writing some graphics routines like drawing lines and circles.  Eventually I wrote a very simple graphics editor with which to create images and save them.

The Game

At the arcade I was heavily into Robotron, Donkey Kong, Defender and Joust, and I basically set off to figure out how to make something similar to Donkey Kong because it seemed the most doable on an Apple II+.  Here’s a description of  Millenium Leaper, approximately in the order the screens appear during play.

All the screen shots can be viewed at full size in Picasaweb.   Presumably the BAUD BANDITS, marked on each text page, are the folks who packaged the game up and put it on the web.  Kudos, whoever you are!

From millenium-leaper

The very first screen you see upon startup is this little beauty.  Apparently it never occurred to me that making the title page appear first might be a good idea.

From millenium-leaper

Should I call the cops?

From millenium-leaper

Instructions.

From millenium-leaper

More instructions.

From millenium-leaper

The title page is animated. The title appears one letter at a time as the aliens run back and forth underneath it making noise.

From millenium-leaper

The game enters a demo mode where it shows each level in action, while it waits for you to remember that you have to hit the ‘1’ or ‘2’ key to select the number of players.

From millenium-leaper

The game commences. Why is the timer set at 9990 instead of 9999? I have no idea!

From millenium-leaper

Level 1 — You control the little man, who runs around trying to collect the numbers 1..9 and finally 0 (because 0 comes after 9 of course). The green blocks disappear if you run over them, which can be used to isolate the aliens since they can’t cross the holes. But if you isolate an alien and later a number appears in that area it can be hard to get the number.  The hole in the bottom floor moves left to right, which makes it difficult to jump when running left to right.

From millenium-leaper

On completion of a level, the screen scrolls down and an elevator drops down (with attending sound effects) to take you up to the next level.

From millenium-leaper

Level 2 — Run up to get the numbers while jumping the rolling barrels. The barrels may fall off the end of each ramp or decide to come down the ladders.

Level 3 is pretty much the same as level 1 except that the floors “slide” left or right as though they were conveyor belts.  It is probably the hardest level to get past, and the least well designed.  The running of the little man is extremely choppy, so it can be hard to transition to the ladders.  I think I was trying too hard to come up with something a bit different that didn’t require a huge amount of additional coding.

From millenium-leaper

Level 5 — Getting a bit random now, by miking up barrels and ramps and whatnot. I haven’t been able to make it to this level in the emulator yet, but if I recall correctly one of the main difficulties was needing to jump between the left and right sides and having to open the parachute quickly.

From millenium-leaper
From millenium-leaper

High scores.  I don’t think they were saved to disk.

Implementation

I don’t recall a lot of specifics about the implementation except that I didn’t know anything at all about game design or good coding style. Abstract data types? Functional decomposition? Never heard of them. You might have noticed that all the surfaces on which the aliens and the little man run are solid white. That’s because I used that to detect where the floors were rather than encoding any sort of model of the virtual world into data structures. That, plus a few rules such as the maximum height of a jump and bouncing off the edge of the screen were all there was.

Using the Apple2Oasis Emulator

  1. Download the emulator and unzip it.
  2. Download the game from here or here and unzip it.
  3. Run the emulator, apl24win.exe
  4. Press Control-F12 to get a BASIC prompt (dunno why)
  5. Press Control-F4 to load a disk image and specify the .dsk file you downloaded in step 2.
  6. Press Control-F1-F12 all at the same time.
  7. Press ‘R’ to choose Run from the menu
  8. Press ‘C’ to choose Millenium Leaper from the menu.

Epilogue

Sometime in 1983 I managed to sell Millenium Leaper to Softdisk magazine for about $300.  That probably works out to about $0.50 per day or around $0.08 per hour.  In 1984 Softdisk offered me a job as a game programmer and flew me down to Shreveport, LA for a look see.  Despite the fact that I was still working on the loading dock at Symbolics at that point, I turned them down.  I was fascinated by the Lisp machines at ‘bolics and I just couldn’t imagine living in Shreveport at the time, though I often wondered how things might have turned out if I had.


[1] Apple II firmware and memory layout


[2] LISA assembler (near bottom)