diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+           DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+                   Version 2, December 2004
+
+Copyright (C) 2004 Sam Hocevar
+ 14 rue de Plaisance, 75014 Paris, France
+Everyone is permitted to copy and distribute verbatim or modified
+copies of this license document, and changing it is allowed as long
+as the name is changed.
+
+           DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. You just DO WHAT THE FUCK YOU WANT TO.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,4 @@
+#!/usr/bin/env runhaskell
+
+> import Distribution.Simple
+> main = defaultMain
diff --git a/bacteria.cabal b/bacteria.cabal
new file mode 100644
--- /dev/null
+++ b/bacteria.cabal
@@ -0,0 +1,18 @@
+name:               bacteria
+version:            1.0
+synopsis:           braindead utility to compose Xinerama backgrounds
+description:        Compose a sequence of images by centering them on rectangles the size of the Xinerama screens available.  Supports jpg, png, and gif input, and produces png output.
+category:           Graphics
+license:            OtherLicense
+license-file:       LICENSE
+author:             Daniel Wagner
+maintainer:         daniel@wagner-home.com
+homepage:           http://www.dmwit.com/bacteria
+bug-reports:        http://dmwit.fogbugz.com/
+package-url:        http://www.dmwit.com/bacteria/bacteria-current.tar.gz
+build-Type:         Simple
+cabal-Version:      >=1.2
+
+executable bacteria
+    main-is:        bacteria.hs
+    build-depends:  base<=5, gd, X11>=1.4
diff --git a/bacteria.hs b/bacteria.hs
new file mode 100644
--- /dev/null
+++ b/bacteria.hs
@@ -0,0 +1,59 @@
+module Main where
+
+import Control.Arrow hiding (right)
+import Data.List
+import Graphics.GD
+import Graphics.X11
+import Graphics.X11.Xinerama
+import System.Environment
+
+fullSize = maximum . map right &&& maximum . map bottom
+bottom (Rectangle { rect_y = y, rect_height = h }) = fromIntegral y + fromIntegral h
+right  (Rectangle { rect_x = x, rect_width  = w }) = fromIntegral x + fromIntegral w
+
+-- TODO: scale down if too large
+addImages background images rectangles = sequence_ $ zipWith (addImage background) (cycle images) rectangles
+addImage background image (Rectangle { rect_x = x, rect_y = y, rect_width = wr, rect_height = hr }) = do
+    (wi, hi) <- imageSize image
+    copyRegion (0, 0) (wi, hi) image
+               (fromIntegral x + fromIntegral wr `div` 2 - fromIntegral wi `div` 2,
+                fromIntegral y + fromIntegral hr `div` 2 - fromIntegral hi `div` 2)
+               background
+
+loadFile imageName = ($ imageName) $ case (take 4 &&& take 5) (reverse imageName) of
+    ("gpj.",_)  -> loadJpegFile
+    (_,"gpej.") -> loadJpegFile
+    ("gnp.",_)  -> loadPngFile
+    ("fig.",_)  -> loadGifFile
+    _           -> error
+
+nameForRectangles = intercalate "-" . map nameForRectangle
+nameForRectangle (Rectangle { rect_x = x, rect_y = y, rect_width = w, rect_height = h }) =
+    show w ++ 'x' : show h ++ '+' : show x ++ '+' : show y
+
+createBackground imageNames = do
+    display    <- openDisplay ""
+    rectangles <- getScreenInfo display
+    images     <- mapM loadFile imageNames
+    background <- newImage (fullSize rectangles)
+    addImages background images rectangles
+    return (background, rectangles)
+
+usage = do
+    name <- getProgName
+    putStr . unlines $ ["Usage: " ++ name ++ " inputImage [inputImage ...] outputName",
+                        "Input images may be .jpg, .jpeg, .png, or .gif files.",
+                        "The output will be written in PNG format to 'outputName-resolution.png'.",
+                        "The name of the output file will be written to stdout."
+                       ]
+
+main = do
+    args <- getArgs
+    case args of
+        []         -> usage
+        [_]        -> usage
+        _          -> do
+            (background, rectangles) <- createBackground (init args)
+            let filename = last args ++ '-' : nameForRectangles rectangles ++ ".png"
+            savePngFile filename background
+            putStrLn filename
