Recently in Software Category

How to process AOL's search logs with PHP

|

AOL, for some reason, released 2,000,000 search records taken from the last 3 months. With a tiny bit of programming, you can use PHP to search through these records. This post describes how.

But first, let's cut to the chase:

First, you need to download the files, which you'll have to find on your own, as I can't remember where I found them. The file is ~450MB.


wget http://whereverthosefilesare.com/AOL-data.tgz

Next, uncompress this file into its multiple parts:


tar zxvf AOL-data.tgz

Then, un-gzip the compressed files:


gzip -f user*.gz

This will leave you with a bunch of text files containing the actual log data. These files will be very large. So large in fact that your web server might not be able to deal with them in PHP. So, you should split them into multiple smaller files. For each .txt file, run a command such as:


csplit -f aol user*01.txt 1000 {1000} &

That code will split the files into multiple files of 1000 lines each, naming each them aol100, aol101 and so on. In these smaller chunks, PHP will be able to deal with them more easily. When I ran this command, I ended up with 2000 files of 1000 lines each. For the code below to work, each of these files must have the letters "aol" in their names.

Next, you can create a PHP page that will search the AOL log files for a certain string, and then return matching lines. The string you are looking for will be passed on the URL, as in http://example.com/search.php?search=sex

Here is the code for the PHP page.

Save the file as search.php or whatever, and then access it at its url, e.g., http://yourwebsite.com/search.php?search=thewordyouarelookingfor

Change the URL to run another search. You can take the user id from one search and put it on the URL, thereby finding all the searches by that user.

outlook with itunes screenshot

Ok, here's one for the masses.

This post describes how to add info about the song currently playing in iTunes to emails you compose in Outlook. Anyone can do it!

First, create the macro. To do so:

  1. Open Outlook.
  2. From the Tools menu, select Macro, then Macros...
  3. In the Macro field, enter a name for your macro. "AddiTunesSig" is probably appropriate. [screenshot]
  4. Click "Create".
  5. A "code window" will open. This is where, in a minute, you will type the code that makes up the macro.
  6. But first, you need to tell Outlook how to talk to iTunes. To do so, go to the Tools menu and select References. Scroll down until you find "iTunes Type Library" or something similar. Select its checkbox and click OK. [screenshot]
  7. Back in the code window, you will see two lines of code: Sub AddiTunesSig() and End Sub. In between these lines, paste in the following code:
    
    
    ' purpose: opens a new mail message, 
    ' appends info re: currently playing track in iTunes
    
    Dim itunes As iTunesApp
    Dim strArtist As String
    Dim strTitle As String
    Dim strOutput As String
    Dim mail As Outlook.MailItem
    
    Set itunes = New iTunesApp
    
    'load the track info into easy-to-read variables
    strArtist = itunes.CurrentTrack.Artist
    strTitle = itunes.CurrentTrack.Name
    strAlbum = itunes.CurrentTrack.Album
    
    'assemble the signature
    strOutput = vbNewLine & "------------------------------"
    strOutput = strOutput & vbNewLine & "Now playing: " & vbCrLf _
         & strTitle & vbCrLf & strArtist & vbCrLf & strAlbum
    
    'create a new email message
    Set mail = Outlook.CreateItem(olMailItem)
    
    'put the signature in the body
    mail.Body = vbNewLine & vbNewLine & strOutput
    
    'show the message to the user
    mail.Display
    
    'clear up the memory
    Set itunes = Nothing
    
    

    See how easy programming is! [screenshot]

  8. To finish up: Click the Save button on the toolbar and close the code window.

Now, you need to add a toolbar button to your Outlook toolbar that will run this macro. To do so:

  1. Go to the Tools menu, and select Customize...
  2. In the dialog box that pops up, scroll down the left side, and click Macros. [screenshot]
  3. You will see your macro on the right ("Project1.AddiTunesSig"). Drag it up to a convenient location on your toolbar. (Next to the "New" button is probably a good place.)
  4. To rename the button, right-click the button and type the new name where it says "Name:" in the pop-up menu. "New (with music)" is probably a good name. [screenshot]
  5. Close the Customize window.

That's it! To use it, open iTunes, play a song, go back to Outlook, and click your new button. A new email will open with info about the currently playing song in the signature area.

Earlier: How to control iTunes from any Microsoft Office application.

Max OS X widget for Radio Paradise playlist

|

radio paradise widget

I made a Mac OS X Dashboard widget that displays the current playlist from RadioParadise.com, a great internet radio station. It's my first ever widget, so it's not very fancy, but it gets the job done.

The widget shows a scrollable list of the last 6 hours worth of music played, and if you click a song title, it opens the web page on RP's site dedicated to that song. Clicking the main logo takes you to RP's site. It refreshes when you show the Dashboard and you can manually refresh it by clicking the "refresh" link. I may add automatic refreshing in some future release.

Once you've downloaded the widget, unzip it by double-clicking it, then double-click the widget file. For older versions of Mac OS X, you might need to move the files into your home folder's /Library/Widgets folder first.

Apple doesn't seem to publicize this fact, but practically anyone can make a widget. Simple widgets are really just small web pages, and can be made using only HTML, JavaScript, and a couple of images. You should give it a try. I just read Apple's excellent tutorial, looked at the source code for one of their RSS-reading sample widgets, and went from there.

This widget uses JavaScript to extract data from an XML version of RP's playlist. I believe it is technically an AJAX-based widget, albeit a very simple one. A few weeks ago, I wrote a PHP script that generates an RSS feed from that XML.

I'm guessing it's trivial to convert Mac OS X widgets to Konfabulator/Yahoo! Widgets, so I will do that when I get a minute.

itunes in excel

Summary

This post describes how to interact with and control iTunes from any Microsoft Office application in Windows. Specifically, it shows how to:

  • Create an Excel spreadsheet that lists all the tracks in your iTunes library, organized by playlist
  • Use an Access database to update the mp3 ID tags of your songs in iTunes
  • Create a Microsoft Word document that lists all your iTunes tracks info in a table
  • Control iTunes playback from any Office application

Downloads

If you don't want to read the boring explanation about how to do these things, and you just want to download the files that already do them, here you go:

  • Excel spreadsheet that loads your iTunes library info and lets you play any selected song
  • Access database that lets you browse your collection, update tags, and control playback
  • Word document that displays all your iTunes tracks in a table

To use the Word and Excel files, run the macros in the Tools:Macro menu. Note that you will probably get all kinds of warnings about macro security and so on when you open the files, so you'll have to figure out how you want to handle that. Or you can also just get the source code from these text files, but you'll need to know how to connect that code to macros, etc. Please also note that these files are offered primarily as tutorials, not as complete applications, so they are likely to be buggy and not fail gracefully. Also, it's probably helpful to open iTunes before opening any of these documents. You can file bug reports in the comments, and I'll try to fix them when I'm able.

Technical Background

Many Windows applications, including iTunes, provide "libraries" of functionalities to other applications. Certains kinds of these libraries are called "COM objects", and they tend to be relatively easy to work with. Fortunately, Apple provides one of these for iTunes, and Visual Basic for Applications (VBA), the scripting language provided with Microsoft Office, can make use it. Using VBA, you can tap into the iTunes COM, and manipulate iTunes objects like playlists, tracks, and even the playback functionality. This post describes how to do so.

Getting Started

Interacting with the iTunes Library

Let's start by connecting a Word document to iTunes, so you can output a list of all the songs in your iTunes library to a Word document.

  1. Open iTunes.
  2. Open Word.
  3. From the Tools menu, select Macro, then Macros.
  4. Type the name of the macro you want to create ("Show_iTunes_Library" might be a good name), and click Create. A VBA editing window will appear. This is where you will type the code that will make up your macro.
  5. Before you can make VBA do anything with iTunes, you need to tell it where to find the library of iTunes functions it can use. From the Tools menu, select References... Go through the list until you find "iTunes 1.2 Type Library", check it, and click OK.
  6. Back in the VBA editing window, paste this text in between the first and last lines of your subroutine:
    
    Dim iTunes As iTunesApp
    Dim tr As IITTrack
    
    Set iTunes = New iTunesApp
    
    For Each tr In iTunes.LibraryPlaylist.tracks
        ActiveDocument.Range.InsertAfter (tr.Name & vbCrLf)
    Next
    
    Set iTunes = Nothing
    
  7. Let's take another look at that code and see what it all does:
    
    'declare an object variable for the iTunes application and an iTunes "track" (song)
    Dim iTunes As iTunesApp
    Dim tr As IITTrack
    
    '"instantiate" the class, i.e., prepare it for use.
    Set iTunes = New iTunesApp
    
    'go through each track in the LibraryPlaylist
    For Each tr In iTunes.LibraryPlaylist.tracks
        'in the active document, insert the track's name (i.e., song title) 
        'and a new line (carriage return/line feed)
        ActiveDocument.Range.InsertAfter (tr.Name & vbCrLf)
    Next
    
    'reset the iTunes object to free up the memory used in this code
    set iTunes = Nothing
  8. Back in your Macros dialog box, click the name of the macro you just created and run it. It should output all the track info in your library to the active document in Word. (There is code in the Word document above that shows how to convert this data into a table automatically.)

This is just a basic example to show how to iterate your iTunes song library in VBA. If you wanted to have more info about each track appear, you can change the tr.Name part to include things like tr.Artist, tr.Album, tr.PlayedDate, etc. The VBA programming environment should display all the properties available to you as you start typing them. For example, if you declare tr as an iTunes track object, when you type tr., all the available properties and actions (aka "methods") will appear in a drop-down selection box text to the variable name.

Controlling iTunes Playback

Similarly, to make the iTunes application itself take certain actions, you can do thing like iTunes.Play or iTunes.Pause, assuming your code has an iTunesApp object called iTunes. The names of the available actions ("methods") will appear when you type the name of the object variable followed by a period.

For example, we can make a simple form in Microsoft Access that will control iTunes playback. This will probably go more smoothly if you've had a little experience designing forms in Access.

  1. Open iTunes.
  2. Open Microsoft Access,
  3. In the database window, choose Forms, and create a new form using Design View.
  4. Add two buttons to the form. Name one cmdPlay and one cmdPause.
  5. Set the captions to "Play" and "Pause" accordingly.
  6. In the properties for cmdPlay, go to the Events tab, and in the On Click property, click "..." to create a new subroutine that will run when the button is clicked.
  7. When the VBA window opens, set your references to the iTunes 1.2 Type Library as described above.
  8. In the subroutine for cmdPlay_Click, enter this code:
    
         Dim iTunes As iTunesApp
         Set iTunes = New iTunesApp
         iTunes.Play
         Set iTunes = Nothing
    
  9. Go back to your form, and in the Click event for cmdPause, create a new subroutine that looks like this:
    
    Private Sub cmdPause_Click()
          Dim iTunes As iTunesApp
          Set iTunes = New iTunesApp
          iTunes.Pause
          Set iTunes = Nothing
    End Sub
    
    
  10. Open your form in Form view, and click the Play button. It should work.

If you want more information on all the iTunes objects, properties, and methods available to you, check out Apple's iTunes Software Development Kit for Windows. You can pretty much ignore all of it except for the help file (iTunesCOM.chm) which, in a somewhat arcane manner, describes each of the classes (objects) and their properties and methods. Unfortunately, the help file is heavy on specification and light on examples, but using the examples and downloadable files I provided above, you should be able to figure it out with a bit of those critical thinking skills you picked up when you were younger.

Next Steps

Once you've figured out how to iterate through the tracks in your library, you are pretty much only limited by your knowledge of how VBA works in each of the Microsoft Office applications. If you know how to use VBA to create new documents, or worksheets, or slides, or address book contacts, or whatever, it's fairly simple to manipulate an iTunes library, playlist, or track to do whatever you want with the Office application of your choice. For example, the downloadable Excel spreadsheet offered above loops through all your playlists, creates a worksheet for each one, and adds the tracks from each playlist to the appropriate spreadsheet, along with the last played date and the play count. It will also play a track when you click on a track name and run the "play track" macro. The Access database provided above shows you track info for the currently playing song, allows you to jump to any song you type in, and lets you update the mp3 tags for the songs in your iTunes Library. The Word document enters all the tracks in your iTunes library into a table. Examine the source code to come up with your own projects, and have fun integrating Microsoft Office with iTunes.

Apple seems to have taken its "real objects" design metaphor a bit too far in the latest version of iTunes, released today. Look at the main display window: it has glare!

itunes display

Now, here's the old one. Notice, no glare:

itunes display

One of the most annoying aspects of real-world electronic devices is the glare on the display. WHY ON EARTH would Apple go out of its way to reproduce this defect on a virtual object? As you can see, it actually divides artist's name in half -- one half on the light side, one half on the dark side. It hinders readability. Why would they do this? Isn't the only explanation "To make it look more real." What's next? Will the buttons in iTunes stop working after 6 months, just like the iPod's click wheel?

This all started with the "brushed metal" and stupid "drawer" device in the Quicktime player (remember that one?), and now it's really gotten out of hand.

I understand that in certain cases, real world metaphors are useful in software design, but the primary advantage of virtual objects is that they are not subject to the limitations/flaws of real world objects. Apple needs to realize that metaphors should be used as guidelines, not absolute rules.

You may recall I half-wrote a script to do this a couple years ago, but I was mostly cribbing from some guy at Apple and really had no idea what i was doing.

Anyway, I'm taking another shot at parsing the iTunes library XML using PHP5's new "SimpleXML" library, which is a terrific feature that I never get tired of working with.

I cooked up this little script in about 10 minutes. The format of Apple's XML files makes it sort of a pain to process in the usual ways, but you can still get reasonable output with just a few lines of code. And most of that code is concerned with formatting, not the actual XML processing.

To use this script:

  1. Make sure you are using PHP5 with SimpleXML support. At Dreamhost, you can turn this on by clicking the "edit" link on the main domain management page. If you're hosting a site on your Mac, you can get an easy-to-install version of PHP5.
  2. In iTunes, select a Playlist or Library, choose "File:Export..." and export it as XML. Name it itunes.xml. (If your site is hosted on your Mac, you can just create a symlink called "itunes.xml" that points to your "iTunes Music Library.xml" file or the playlist file you just exported. Place this link in your website directory.)
  3. Upload itunes.phps and itunes.xml to your webserver.
  4. Rename itunes.phps to itunes.php.
  5. Open your browser and navigate to itunes.php.

Obviously there are lots of ways to enhance the functionality of this script, but this will get you started.

I was interested in using PHP5's DOM extension to create RSS feeds, but I couldn't find a decent tutorial on the web about how to do that. Most of the things out there involve PHP4's DOM-XML, which is different in some key ways. Even PHP.net lacks basic examples of how to use even the most fundamental DOM methods.

So I puzzled my way through it, using the sparse examples at PHP.net and the old DOM-XML samples for creating generic XML docs, trying to find the matching methods in the current DOM reference.

Once you've figured out how to create and append one node, the rest is pretty easy. So here is a sample feed generated by PHP and DOM, and here is the heavily commented source code that produces it.

This script demonstrates how to use DOM to create an RSS feed from items that are manually entered into an array. It's pretty easy to adapt the code to use a database to automatically enter those items into an array: all you'd have to do is query the database, add your items to an array, and substitute that array for the one manually generated in my script. (For the sake of completeness, I will post a script that does this when I get a few minutes.) Update: You can see an example of this fully automatic technique in this Ning app I created.

Nmap'ing Tivo

|

I don't know why I never thought of doing this before.

$ nmap -sT -sR -sV -I -O -PI -PT 192.168.1.103

results

This is probably the first of several posts that will deal with this topic.

The new Tivo system software upgrade brings many interesting features to Tivo, the most well-known of which is TivoToGo, which lets you copy the video files to your PC.

However, the software upgrade also includes a web server. This means you can interact with your Tivo via any web browser on any PC. I won't discuss all the ramifications of this right now, but one notable one is that Tivo can now produce your "Now Playing" list (a list of everything on your Tivo) as either an HTML or XML file.

The XML file is particularly exciting, because XML is very, very easy to parse nowadays. People have already parsed this XML into RSS, and I expect to be doing the same over the next couple of days.

To access your Tivo's Now Playing list as an XML file, use this URL:
https://192.168.1.103/TiVoConnect?Command=QueryContainer&Container=%2FNowPlaying
Just change the IP to the address of your Tivo, then login using the username tivo and your Media Access Key as your password.

Some of the scripts other people have released to parse this file are quite elaborate (and cool), but I wanted to demonstrate how easy it is to parse the Now Playing list into a simple HTML stream that could be easily included on any website. This took me about 10 mins to write, and it isn't very elegant.

Here you go:

<?php
function converttivodate($format, $input){
        //borrowed from A. Cassidy Napoli's Tivo_XML script
        return date($format, hexdec($input));}

$file = "nowplaying.xml";
$sxe = simplexml_load_file($file);
foreach($sxe->Item as $item) {
        $details = $item->Details;
        echo "$details->Title: $details->EpisodeTitle<br/> 
	$details->Description (" .
	converttivodate('n/d/y G:i',$details->CaptureDate) . 
	", $details->SourceStation, $details->SourceChannel)</p>\n"; } 
?>

That's about 6 lines of PHP, and it's easy to see the same (or even more) could probably be accomplished in about 2 lines. (See the update below.)

Just use include() or the Curl extensions to include the file on your site, and you're all set. This code snippet requires PHP5's SimpleXML support.

It produces something like this:

Law & Order: Merger
A scandal involving two wealthy families threatens McCoy and Carmichael's chances of a conviction in the murder of a drug-addicted girl of 15. (1/26/05 15:59, TNT, 3-0)

Seinfeld: The Doorman
A doorman (Larry Miller) tries to cause trouble for Jerry; Kramer develops a male undergarment. (1/26/05 15:29, TBS, 22-0)

Malcolm in the Middle: Reese's Apartment
Francis is determined to show his parents why they should not have kicked Reese out; Malcolm helps a football player writer a college essay. (1/26/05 14:59, WWOR, 9-0)

Here's a demo:

Update (1/27/05): Well, if you're willing to sacrifice readability in the code, you can implement the above with just 2 lines of PHP. I just took out the extra function call and variable assignments from the code above, and wound up with two lines.

When you take a picture with a digital camera, most cameras store some data along with the picture, such as the date and time you took the photo, whether you used the flash, the focal length, the f-stop, and the make and model of the camera. This information is called EXIF data.

I thought it would be useful to be able to automatically publish this data in an RSS or Atom feed, so I wrote a PHP script to do just that.

My script, named Asif, will process a directory containing JPEGs and output an HTML, RSS, or Atom feed containing some or all of the Exif data for each picture, as well as (optionally) a thumbnail version of the picture.

See it in action:

This demo processes the files in this directory. The thumbnails are generated dynamically, as needed. (The good pictures are from manyhighways.com.)

Asif has two primary benefits:

  • It allows you to instantly generate a gallery from a directory full of images without having to write a single line of HTML or set any configuration options. To accomplish this, just drop asif.php into a directory, and access the page.
  • It allows you to instantly provide an RSS or Atom feed containing Exif data for any directory full of photos. You could use this for a photoblog, or, really, for instantly creating a photoblog by just dropping your photos into a directory on your server and renaming asif.php to index.php and pointing readers to that directory. Your gallery will automatically update every time you drop a file in the directory, and the RSS/Atom feed will always be fresh.

The output format is controlled by the user. Simply append the name of the format to the URL, and you get what you asked for. So, http://yourdomain.com/photos/asif.php?format=rss gets you RSS, and asif.php?format=atom gets you Atom. Omitting the format parameter produces HTML.

Similarly, the user controls whether to display thumbnails: asif.php?thumbnails=yes displays them. Omitting that parameter omits them. If thumbnails are requested, they will be included in the RSS or Atom feeds as well.

Asif can handle any directory path you pass to it on the URL. So, asif.php?format=rss&directory=sample will process the web directory called "sample". Directory paths are relative to the path of the script. So, asif.php?format=rss&directory=sample/travel/nyc will go down three directories and display the images. Omitting the directory directive tells Asif to display the data for the current directory.

Cameras often store far more Exif data than is really useful, such as manufacturers' notes that are essentially encoded gibberish. For this reason, Asif by default will only show you certain Exif fields. However, if you wish to see all available Exif data for a file, pass the directive &alldata=yes on the URL, and Asif will return everything it finds in the file.

By default, Asif produces valid XHTML 1.0, valid RSS 2.0, and valid Atom .3. As long as you don't have any weird stuff mixed into your Exif data, it should always validate. The appearance of the HTML is controlled entirely via CSS, which of course you can customize.

Requirements

Asif requires PHP5, compiled with the GD libraries and with the directive --enable-exif. However, I believe only one line of code -- a call to scandir() -- needs to be rewritten to work in PHP4. (I included the alternate PHP4-compliant code in the comments.) If you don't have PHP5 installed on your server, I discuss how to do so in another post.

Installation

  1. Get the source code.
  2. Get the CSS file asif.css so you can control the HTML formatting.
  3. Install both files in a directory on your webserver, and rename asif.phps to asif.php.

It will be instantly ready to use, assuming the GD and Exif libraries are working on your server. If desired, change the constants defined at the top of the file to meet your needs.

Asif is free software and covered by the GPL.

Using Asif

Asif is controlled by passing parameters on the URL. These parameters are described above and in the source code. Available parameters are: format, directory, alldata, and thumbnails.

  • format can be "RSS", "Atom", or "HTML". It defaults to HTML.
  • directory is the path you want to process. Omit the trailing slash on the path. For security reasons, Asif does not, by default, process directories above the one where the Asif script resides. So, if asif.php is in yourdomain.com/photos/galleries/travel/, you can't do something like asif.php?directory=../sports to display photos in /galleries/sports. Instead, put asif.php in the galleries directory, and pass the directory name on the url, like asif.php?directory=sports or asif.php?directory=travel. Get it? Also, if you omit the directory parameter, Asif processes whatever directory it resides in.
  • alldata can be "yes" or "no"/left blank. It defaults to "no." If set to yes, alldata will show all available Exif data for each file. If left blank or set to something other than "yes", it will only show certain common pieces of Exif data: date/time taken, filesize, height/width, f-stop, camera model, ISO, flash, focal length, and user comment. It is not hard to customize the code to add or omit these fields.
  • thumbnails can be "yes" or "no"/left blank. If set to "yes," thumbnails will be generated (if necessary) and displayed. They will be included in the RSS or Atom feeds as img tags, with the src attribute pointing to the URL for the thumbnail, and the link tags pointing to the URL for the full image.

Support

If you have questions or comments, please post them below.

Disclaimer

I am not the world's greatest PHP programmer. The code is inefficient, it may not work, and it may expose your server to security risks. Be sure to read all of the comments in the code, and secure your own webserver properly. Use this software at your own risk. It is offered without warranty or assumption of liability.

Update (2005-02-09): I figured out how to generate RSS feeds using PHP5's DOM support, which I recommend using. When I get some time, I will update this script to use the DOM.

RSS and Atom feeds for RadioParadise.com ++

| | Comments (2)

Update (2006-01-16): I completely revised the code that generates the RSS 2.0 feed. It is much more stable, since it uses a Radio Paradise-generated XML feed as its source, and creates the feed using the DOM. Please use the new feed. Here is the source code.

...

My friend Mike recently introduced me to Radio Paradise, an internet radio station that plays commercial-free indie-rock, with some classic stuff thrown in. I became addicted to it almost immediately, in part because it's great music to have on in the background when you're working on other things, and you're guaranteed to be exposed to all kinds of stuff you've never heard before.

Radio Paradise has a page that lists its most recently played songs, going back about 6 hours. I thought an RSS feed of this page might be useful/enjoyable for some people, including me, but Radio Paradise doesn't offer such a feed yet. So, I spent a few hours last night writing a PHP script that "scrapes" the "recently played" page, and translates it into an RSS feed. Update: I also wrote a script that creates a feed for RP's recently active forums list.

Update (10/27/04): I have released the source code for this project. This allows you to generate the playlist feed from your own website. The only requirements are that your server can run PHP with the CURL functions. All you have to do is copy this file to your server, remove the final "s" from "feed.phps" and access it in your browser or RSS reader. Note there are some slight constraints on your redistribution and use of the code. Please see the comments in the file.

Progammers will notice that a single script determines whether to return an RSS feed or an Atom feed, as determined by a parameter the user passes on the URL. I think this is somewhat uncommon.

The feed will generate automatically every time you access it. In other words, it will be in perfect synchronization with Radio Paradise's page as long as you refresh it.

Now that the information is in this standard format, I'm sure someone could write another script to do something interesting with it, or you can just add it to your RSS/Atom news aggregator, and see what the station has been playing, without having to visit its website.

The script is more stable than it was at first, but I would still expect bugs from time to time, including critical ones. Email me any bug reports, and I'll see what I can do.

If you use this feed, please leave a comment, so I can report your interest to the Radio Paradise staff, who are aware of this project.

About this Archive

This page is a archive of recent entries in the Software category.

Tivo is the next category.

Find recent content on the main index or look in the archives to find all content.

Powered by Movable Type 4.0