Static Gists With Lisp

Here's a Common Lisp function to generate static HTML and CSS from a GitHub Gist URL. The results are printed to standard out, and can be copy/pasted into an HTML document. This is really useful when working in Emacs with a Slime REPL open.

(defun make-static-gist (gist-url) 
  "Retrieve a Gist from GitHub and format it as static CSS and HTML."
  (let* ((nl-string (format nil "~c" #\newline))
         ;; Make sure the url has ".js" on the end
         (ending (subseq gist-url (- (length gist-url) 3)))
         (js-url (if (string= ending ".js")
                     (concatenate 'string gist-url ".js")))
         ;; Fetch the embedded gist from GitHub
         (gist-data (drakma:http-request js-url)))
    ;; Read the string data
    (with-input-from-string (strm gist-data)
      (let* (
             ;; Get the CSS link
             (css-html (read-line strm))
             ;; Get the document data
             (doc-part (read-line strm))
             ;; Parse out the CSS URL and fetch it
             ;; 45 is the length of "document.write...",
             ;; 4 is the length of "\");" on the end
             (css-url (subseq css-html 45 (- (length css-html) 4)))
             (style-sheet (drakma:http-request css-url))
             ;; Remove \n and \ from the html
             (escaped-html (subseq doc-part 16 (- (length doc-part) 4)))
             (html-nl (cl-ppcre:regex-replace-all "\\\\n" escaped-html nl-string))
             (raw-html (cl-ppcre:regex-replace-all "\\" html-nl "")))
        ;; Print everything out
        (format t "~a~%" style-sheet)
        (format t "~a~%" raw-html)))))

New Github Pages Site

I haven't really done anything with my GitHub pages site, except setup Octopress and publish one blog post. Every time I've wanted to add a new entry I've got distracted fucking with Octopress and Ruby and Jekyll and a bunch of other stuff I don't care to learn, and ended up losing my motivation.

This time it happened again, and I've decided to just get rid of Octopress and Jekyll entirely and go back to raw HTML. It won't be the trendiest, prettiest website on the internet, but at least I know how to use it, and it won't have random shit breaking requiring an hour of tinkering to figure out which of a million Ruby gems is broken or not installed.

Gpx Library

I recently wrote a small library, called gpxtools, for processing GPX track files in Common Lisp.

It doesn't have many features yet, but right now it can read a GPX file and compute elevation gain, elevation loss, and the total distance of all the tracks in the file.

Here is a sample usage from the REPL:

* (ql:quickload 'gpxtools)
   To load "gpxtools":
   Load 1 ASDF system:
   ; Loading "gpxtools"
* (defparameter *gpx*
    (gpxtools:read-gpx "/Users/jeremiah/gpx_tracks/precarious_climb.gpx"))
Processing track: ACTIVE LOG
* (gpxtools:summarize *gpx*)
Total elevation gain: 3567.271946242661d0 feet
Total elevation loss: -3538.885209324304d0 feet
Total elevation loss: 6.437161570619994d0 miles

So far the most challenging part of the project was the calculation of distances given points in latitude and longitude. Doing so requires converting the coordinates to the Universal Transverse Mercator coordinate system which uses meters, and then calculating the distance.

I wasn't able to find a library to do the conversion for me, so I wrote my own, and requested it be added to QuickLisp. It looks like everything went well, and it should be in the next release.

I'm planning to add more features to the gpxtools library, and to clean up the code in a few spots.

One thing I want to do is add generic traversal code and use it to simplify functions like distance, elevation-gain, and elevation-loss that iterate over the entire GPX data structure. Another thing I want to add is the ability to split tracks at a certain location and selectively write the results back to one or more files. I'll often start my GPS at the beginning of a hike, but forget to turn off the GPS when I finish hiking and drive away. The result is a GPX track with 10 miles of hiking and 50 miles of driving. I may even try to do the cut automatically, ending the track when it gets back to (or reasonably close to) the origin, and splitting the drive out into a second track automatically.