Mashups Using Clojure
Turkey sits on top of the North Anatolian Fault, so earthquakes are something that happens a lot here. This mashup was one of the first problems I tackled in Clojure, I was going to throw it away but figured it may be use to someone else or to me later on.
Kandilli observatory and earthquake research institute releases latitude, longitude and magnitude information for the the last 200 earthquakes, so I grabed the list of earthquakes from their site, and pin them on Google Maps, that way I got a nice visual representation.
The data we are interested in looks like the following,,
Date Time Latit(N) Long(E) Depth(km) MD ML MS Region ---------- -------- -------- ------- ---------- ------------ ----------- 2009.12.17 04:56:13 37.4865 35.6947 4.0 3.4 -.- -.- KOZAN
So we begin with a structure to hold the earthquakes,
(ns eartquake (:use clojure.contrib.str-utils) (:use clojure.contrib.duck-streams) (:use clojure.contrib.prxml) (:import (java.net URL) (java.io BufferedReader InputStreamReader))) (defstruct earth-quake :date :time :latitude :longitude :depth :md :ml :ms :location)
Then we need to grab the page containing the data we are interested in,
(defn fetch-url[address] (let [url (URL. address)] (with-open [stream (.openStream url)] (let [buf (BufferedReader. (InputStreamReader. stream "windows-1254" ))] (apply str (interleave (line-seq buf) (repeat \newline )))))))
We take each line and split it into nine parts not ten because last column is variable length, and apply the struct on it, that way we get a vector of earthquake structures.
(defn parse [data] (map #(apply struct earth-quake (re-split #"\s+" % 9)) (re-split #"\n+" data)))
The data portion of the page we are interested in begins just before the first earthquake with the dashes up to the closing pre tag, a simple regex will match it, and pass it to parse,
(defn eartquakes  (let [page (fetch-url "http://www.koeri.boun.edu.tr/scripts/lst9.asp") data (re-find #"(?s)------------ -----------\n(.*?)</pre>" page)] (parse (data 1))))
(defn markers [earth-quakes] (map #(str "createMarker(" (:latitude %)","(:longitude %) ",'" (apply str (interleave % (repeat "<br>"))) "');") earth-quakes))
This will result in 200 createMarker calls, which will be placed into the resulting web page. Following template is bare minimum that is required to show a google map with the addition of the createMarkers function,
This will switch the map to satellite view, center it roughly on the center of Turkey and place the markers on the map, all that is needed now is to spit out a html file containing all the data,
(defn mash-up  (spit "mash.html" (with-out-str (prxml (template (eartquakes))))))
Of course it is not practical to click on a HTML file every time we want to view the data so we need a function to automatically show the spited file, this will only work on Mac OS X but I am sure there is way to achieve the same effect on other OSs.
(defn show  (mash-up) (.exec (Runtime/getRuntime) "open mash.html"))